Skip to content

[AI Refactoring] SafeUsbHandle.ReleaseHandle → Destroy() 의 ThrowIfFailed → finalizer/CER 경로 예외 throw 로 프로세스 강제 종료 위험 (핸들 3종) [Scope: src/Tizen.System.Usb] (2026-08-09) #7796

Description

@JoonghyunCho

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

Observation

SafeUsbHandle.ReleaseHandle()은 추상 메서드 Destroy()를 호출하고, 모든 Destroy() 구현이 실패 시 ThrowIfFailed(...)로 예외를 던집니다.

// Interop.SafeUsbHandle.cs
protected override bool ReleaseHandle()
{
    Destroy();
    SetHandle(IntPtr.Zero);
    return true;
}
// Interop.Context.cs — UsbContextHandle (static, 프로세스 수명)
public override void Destroy()
{
    if (nativeDevListPtr != IntPtr.Zero)
    {
        FreeDeviceList(nativeDevListPtr, true).ThrowIfFailed("Failed to free native device list");
        nativeDevListPtr = IntPtr.Zero;
    }
    Destroy(handle).ThrowIfFailed("Failed to destroy native context handle");
}

// Interop.Context.cs — HostHotplugHandle
public override void Destroy()
{
    UnsetHotplugCb(handle).ThrowIfFailed($"Failed to unset hot plug callback");
}

// Interop.Configuration.cs — UsbConfigHandle
public override void Destroy()
{
    ConfigDestroy(handle).ThrowIfFailed("Failed to destroy native HostConfig handle");
}

Problem

  • Coding Guidelines (SafeHandle 계약 위반): SafeHandle.ReleaseHandle은 제약 실행 영역(critical finalization)에서 호출되며 절대 예외를 던져서는 안 되고, 실패는 return false로 알리는 것이 계약입니다. 현재 구조에서는 네이티브 해제 실패가 곧바로 예외가 됩니다.
  • 결함 위험 (finalizer 스레드 크래시): UsbConfiguration(ActiveConfiguration/Configurations getter마다 새 UsbConfigHandle 생성)이나 UsbManager를 Dispose 하지 않고 GC에 맡기면 finalizer 스레드에서 ReleaseHandle → Destroy → throw 경로가 실행되고, finalizer 스레드의 미처리 예외는 프로세스를 즉시 종료시킵니다. static인 UsbContextHandle은 프로세스 종료 시점 정리 중 예외를 던져 정상 종료를 크래시로 바꿀 수 있습니다. UsbManager.Dispose(false) 경로도 finalizer에서 HostHotplugHandle.Dispose()를 호출하므로 동일 위험이 있습니다.
  • 동일 유형 선례: [AI Refactoring] WiFiDirect finalizer 경로 2곳 예외 throw (WiFiDirectThreadLocal 소멸자 + Dispose(false)→Deinitialize) → finalizer 스레드 프로세스 강제 종료 위험 [Scope: src/Tizen.Network.WiFiDirect] (2026-08-02) #7783 (WiFiDirect finalizer 경로 예외 throw → finalizer 스레드 프로세스 강제 종료 위험).

Proposed Improvement

Destroy()가 예외를 던지지 않고 성공 여부를 반환하도록 바꾸고(internal 타입이므로 시그니처 변경 안전), ReleaseHandle이 그 결과를 반환하게 합니다. 진단은 WarnIfFailed로 유지합니다.

Before/After (핵심부):

// Before
public abstract void Destroy();
protected override bool ReleaseHandle()
{
    Destroy();
    SetHandle(IntPtr.Zero);
    return true;
}

// After
public abstract bool Destroy();   // 실패 시 false (throw 금지)
protected override bool ReleaseHandle()
{
    bool released = Destroy();
    SetHandle(IntPtr.Zero);
    return released;              // false 반환 시 releaseHandleFailed MDA 로 진단
}

// 구현 예 — HostHotplugHandle
public override bool Destroy()
{
    return UnsetHotplugCb(handle).WarnIfFailed("Failed to unset hot plug callback");
}

// 구현 예 — UsbConfigHandle
public override bool Destroy()
{
    return ConfigDestroy(handle).WarnIfFailed("Failed to destroy native HostConfig handle");
}

UsbContextHandle.DestroyFreeDeviceList/Destroy(handle) 결과를 WarnIfFailed로 취합해 반환합니다. HostDeviceHandle.Destroy(현재 no-op)는 return true로 정리합니다.

Target Files

  • src/Tizen.System.Usb/Interop/Interop.SafeUsbHandle.cs
  • src/Tizen.System.Usb/Interop/Interop.Context.cs
  • src/Tizen.System.Usb/Interop/Interop.Configuration.cs
  • src/Tizen.System.Usb/Interop/Interop.Device.cs

Expected Impact (Quantitative Metrics)

  • finalizer/CER 경로에서 예외를 던질 수 있는 Destroy() 구현: 3곳 → 0 (UsbContextHandle, HostHotplugHandle, UsbConfigHandle)
  • finalizer 스레드 미처리 예외로 인한 프로세스 강제 종료 경로: 제거
  • 명시적 Dispose() 경로의 예외 방출: 제거 (Dispose는 던지지 않아야 한다는 가이드라인 충족)

API Compatibility Check

  • Public API signature 변경: 없음 (SafeUsbHandle/Destroy는 internal 타입 내부)
  • 동작 변경: 공개 동작 없음 — 핸들 해제 실패가 예외 대신 경고 로그 + releaseHandleFailed 보고로 전환 (finalizer 크래시 결함 제거)
  • Tizen API Level 하한: 유지 (신규 API 미사용)

Impact Scope

  • Destroy() 구현부 4곳 + ReleaseHandle 1곳, 전부 동일 어셈블리 internal
  • 다른 어셈블리 영향: 없음

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