Skip to content

[AI Refactoring] VoiceControlClient 인식 결과 콜백의 IntPtr != null 항상-참 비교(CS0472) → NULL 포인터 가드 무력화 + 네이티브 콜백 내 예외 전파 크래시 경로 [Scope: src/Tizen.Uix.VoiceControl] (2026-08-09) #7798

Closed

Description

@JoonghyunCho

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

Observation

VoiceControlClient.RecognitionResult 이벤트의 네이티브 콜백은 NULL 포인터를 거르려는 의도로 다음 가드를 사용합니다.

// VoiceControlClient.cs — RecognitionResult add 경로
s_resultDelegate = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
{
    Log.Info(LogTag, "Recognition Result Event Triggered");
    if ((cmdList != null) && (result != null))   // IntPtr(struct) vs null — 항상 true
    {
        RecognitionResultEventArgs args = new RecognitionResultEventArgs(new RecognitionResult(evt, cmdList, result));
        _recognitionResult?.Invoke(null, args);
    }
    else
    {
        Log.Info(LogTag, "Recognition Result Event null received");   // 도달 불가 (dead code)
    }
};

cmdList/result는 값 타입 IntPtr이므로 != null 비교는 nullable-lifted 연산으로 컴파일러가 항상 true로 평가합니다(경고 CS0472). NULL 네이티브 포인터가 와도 else 분기는 절대 실행되지 않습니다.

같은 파일의 GetResult()용 콜백(s_resultCb)은 아예 가드 없이 new RecognitionResult(evt, cmdList, result)를 호출합니다.

Problem

  • Coding Guidelines / 결함 위험: 네이티브가 NULL cmdList를 전달하면 가드를 그대로 통과하여 RecognitionResult 생성자 → new VoiceCommandList(new SafeCommandListHandle(IntPtr.Zero)) → 내부 생성자의 VcCmdListForeachCommands(zero handle)가 InvalidParameter로 실패 → ExceptionFactory.CreateException 예외가 네이티브 콜백 프레임 안에서 throw 됩니다. P/Invoke reverse-callback 경계를 넘는 예외 전파는 정의되지 않은 동작(대부분 프로세스 크래시)입니다.
  • Clean Code: else 분기("null received" 로그)는 도달 불가능한 dead code이며, 의도(NULL 방어)와 구현이 불일치합니다.

Proposed Improvement

IntPtr.Zero 비교로 가드를 정상화하고, GetResult() 콜백에도 동일 가드를 추가하며, 네이티브 경계를 넘는 예외가 없도록 콜백 본문을 방어합니다.

Before:

if ((cmdList != null) && (result != null))

After:

s_resultDelegate = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
{
    Log.Info(LogTag, "Recognition Result Event Triggered");
    if (cmdList != IntPtr.Zero && result != IntPtr.Zero)
    {
        try
        {
            var args = new RecognitionResultEventArgs(new RecognitionResult(evt, cmdList, result));
            _recognitionResult?.Invoke(null, args);
        }
        catch (Exception e)
        {
            // 네이티브 콜백 경계를 넘는 예외 전파는 UB — 로그로 봉인
            Log.Error(LogTag, $"Recognition Result Event handling failed: {e}");
        }
    }
    else
    {
        Log.Info(LogTag, "Recognition Result Event null received");
    }
};
// GetResult() 콜백에도 동일 가드 적용
s_resultCb = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
{
    if (cmdList != IntPtr.Zero && result != IntPtr.Zero)
    {
        s_recognitionResult = new RecognitionResult(evt, cmdList, result);
    }
};

Target Files

  • src/Tizen.Uix.VoiceControl/Tizen.Uix.VoiceControl/VoiceControlClient.cs

Expected Impact (Quantitative Metrics)

  • 항상-참(CS0472) 비교: 2곳 → 0
  • NULL 네이티브 포인터 시 네이티브 콜백 프레임 밖으로 예외가 새는 크래시 경로: 2곳 → 0 (이벤트 콜백 + GetResult 콜백)
  • 도달 불가 dead 분기: 1곳 → 0 (가드 정상화로 실제 도달 가능해짐)

API Compatibility Check

  • Public API signature 변경: 없음 (콜백 내부 구현만)
  • 동작 변경: 없음 — 정상 입력 경로 동일, NULL 입력 시 크래시 대신 이벤트 스킵(원래 의도된 동작)
  • Tizen API Level 하한: 유지 (신규 API 미사용)

Impact Scope

  • VoiceControlClient.cs 내 콜백 2곳, 동일 어셈블리
  • 다른 어셈블리 영향: 없음

Activity

  1. github-actions commented on Oct 8, 2026

    @github-actions
    Contributor

    This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions