Skip to content

[AI Refactoring] InputMethodEditor Set*Callback 5곳 트램폴린 널 가드 부재 + 등록 후 할당 순서 → 네이티브 콜백 내 NRE 크래시 경로 [Scope: src/Tizen.Uix.InputMethod] (2026-08-16) #7804

Open

Description

@JoonghyunCho

[Type: Refactoring]
[Scope: src/Tizen.Uix.InputMethod]
[Priority: 🔴 Critical]
[Lens: Coding Guidelines, Clean Code]

Observation

InputMethodEditor의 콜백 설정 메서드 5곳이 모두 동일한 결함 패턴을 공유합니다:

  • SetLanguageRequestedCallback (InputMethodEditor.cs:1495-1509)
  • SetProcessKeyCallback (InputMethodEditor.cs:1520-1532)
  • SetDataRequestedCallback (InputMethodEditor.cs:1541-1557)
  • SetGeometryRequestedCallback (InputMethodEditor.cs:1566-1583)
  • SetProcessKeyCallback(keycode 오버로드) (InputMethodEditor.cs:2259-2271)
public static void SetLanguageRequestedCallback(OutAction<string> languageRequested)
{
    _imeLanguageRequestedDelegate = (IntPtr userData, out IntPtr langCode) =>
    {
        string language;
        _languageRequestedDelegate(out language);        // (1) 널 가드 없음
        langCode = (IntPtr)Marshal.StringToHGlobalAnsi(language);
    };
    ErrorCode error = ImeEventSetLanguageRequestedCallbackCb(_imeLanguageRequestedDelegate, IntPtr.Zero); // (2) 등록 먼저
    ...
    _languageRequestedDelegate = languageRequested;      // (3) 할당은 등록 후
}

Problem

Coding Guidelines / 버그 리스크 렌즈 — 트램폴린이 네이티브 콜백 스택에서 실행되는데, 관리 예외가 네이티브로 전파되면 프로세스가 즉시 비정상 종료됩니다 (VoiceControl #7798과 동일 계열).

  1. 등록 → 할당 순서 역전: 네이티브 콜백 등록(ImeEventSet*Cb)이 사용자 델리게이트 필드 할당보다 먼저 수행됩니다. 등록 직후~할당 직전 창구간에 콜백이 도착하면 _languageRequestedDelegate가 아직 null → NRE가 네이티브 콜백 내부에서 발생 → 크래시.
  2. 널 가드 부재: 5곳 모두 트램폴린이 사용자 델리게이트를 무조건 호출합니다. 재설정/해제 목적으로 null이 전달되어도 등록은 그대로 진행되어, 이후 모든 네이티브 호출이 NRE 크래시 경로가 됩니다.
  3. 사용자 출력 미검증: SetDataRequestedCallback 트램폴린은 사용자 콜백이 out dataArr = null을 반환하면 dataArr.Length에서 NRE — IME 데이터 미보유 시 null 반환은 자연스러운 사용 방식이라 실사용 트리거 가능성이 높습니다.
_imeImDataRequestedDelegate = (IntPtr userData, out IntPtr data, out uint dataLength) =>
{
    byte[] dataArr;
    _imDataRequestedDelegate(out dataArr);
    data = Marshal.AllocHGlobal(dataArr.Length);   // dataArr == null → NRE → 네이티브로 전파 → 크래시
    ...
};
  1. 예외 격리 부재: 사용자 콜백(processKey, geometryRequested 등)이 던진 예외가 그대로 네이티브 경계를 넘습니다.

Proposed Improvement

패턴 통일 (5곳 공통):

// After — SetDataRequestedCallback 예
public static void SetDataRequestedCallback(OutArrayAction<byte> imDataRequested)
{
    _imDataRequestedDelegate = imDataRequested;               // 1) 할당 먼저
    if (_imeImDataRequestedDelegate == null)                  // 2) 트램폴린은 1회만 등록
    {
        _imeImDataRequestedDelegate = (IntPtr userData, out IntPtr data, out uint dataLength) =>
        {
            data = IntPtr.Zero;
            dataLength = 0;
            try
            {
                byte[] dataArr = null;
                _imDataRequestedDelegate?.Invoke(out dataArr); // 3) 널 가드
                if (dataArr != null && dataArr.Length > 0)     // 4) 출력 검증
                {
                    data = Marshal.AllocHGlobal(dataArr.Length);
                    Marshal.Copy(dataArr, 0, data, dataArr.Length);
                    dataLength = (uint)dataArr.Length;
                }
            }
            catch (Exception e)                                // 5) 네이티브 경계 예외 격리
            {
                Log.Error(LogTag, $"DataRequested callback failed: {e}");
            }
        };
        ErrorCode error = ImeEventSetImdataRequestedCb(_imeImDataRequestedDelegate, IntPtr.Zero);
        if (error != ErrorCode.None)
            Log.Error(LogTag, $"Add SetDataRequestedCallback Failed with error {error}");
    }
}

SetLanguageRequestedCallback(langCode = IntPtr.Zero 기본), SetGeometryRequestedCallback(0 사각형 기본), SetProcessKeyCallback 2종(return false 기본)에 동일 적용.

Target Files

  • src/Tizen.Uix.InputMethod/Tizen.Uix.InputMethod/InputMethodEditor.cs

Expected Impact (Quantitative Metrics)

  • 네이티브 콜백 내 NRE/예외 전파 크래시 경로: 5곳 → 0곳
  • 트램폴린 재생성/재등록: 재호출 시 클로저 재할당 5곳 → 0 (1회 등록 후 필드 스왑)
  • 콜백 미설정 창구간(등록~할당 사이) 레이스: 5곳 → 0

API Compatibility Check

  • Public API signature change: 없음
  • Behavior change: 크래시하던 경계 조건이 안전 기본값(빈 데이터/false/무시)으로 변경 — 정상 경로 동작 동일
  • Tizen API Level floor: 유지 (신규 API 미사용)

Impact Scope

  • 수정 심볼 호출부: 모듈 내부 5개 메서드 본문 한정, public 표면 불변
  • 다른 어셈블리 영향: 없음
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions