Repository navigation
[AI Refactoring] InputMethodEditor Set*Callback 5곳 트램폴린 널 가드 부재 + 등록 후 할당 순서 → 네이티브 콜백 내 NRE 크래시 경로 [Scope: src/Tizen.Uix.InputMethod] (2026-08-16) #7804
Copy link
Copy link
Open
Labels
Description
[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과 동일 계열).
- 등록 → 할당 순서 역전: 네이티브 콜백 등록(
ImeEventSet*Cb)이 사용자 델리게이트 필드 할당보다 먼저 수행됩니다. 등록 직후~할당 직전 창구간에 콜백이 도착하면_languageRequestedDelegate가 아직 null → NRE가 네이티브 콜백 내부에서 발생 → 크래시. - 널 가드 부재: 5곳 모두 트램폴린이 사용자 델리게이트를 무조건 호출합니다. 재설정/해제 목적으로 null이 전달되어도 등록은 그대로 진행되어, 이후 모든 네이티브 호출이 NRE 크래시 경로가 됩니다.
- 사용자 출력 미검증:
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 → 네이티브로 전파 → 크래시
...
};- 예외 격리 부재: 사용자 콜백(
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 표면 불변
- 다른 어셈블리 영향: 없음
Reactions are currently unavailable
Activity