Skip to content

[AI Refactoring] AccountService.AccountUpdated 구독 경로 결함 — 네이티브 콜백 내 미가드 핸들러 호출(크래시 경로) + CreateAccountSubscriber 반환 미검증 + remove 접근자 throw + 무동기화 정적 이벤트 [Scope: src/Tizen.Account.AccountManager] (2026-09-01) #7822

Open

Description

@JoonghyunCho

[Type: Refactoring]
[Scope: src/Tizen.Account.AccountManager]
[Priority: 🔴 Critical]
[Lens: Coding Guidelines, Performance]

Observation

AccountService.AccountUpdated 정적 이벤트의 구독/통지 경로(AccountService.cs:618-682)에 결함 4건이 겹쳐 있습니다.

(a) 네이티브 콜백에서 미가드 사용자 핸들러 호출 — 크래시 경로

private static readonly Interop.AccountService.SubscribeCallback s_accountUpdatedCallback =
    (string eventType, int accountId, IntPtr userData) =>
{
    AccountErrorFactory.CheckAccountFeature();          // ← 콜백 내 불필요 native feature 조회 + throw 경로
    var eventArgs = new AccountSubscriberEventArgs(eventType, accountId);
    s_accountUpdated?.Invoke(null, eventArgs);          // ← 구독자 예외가 네이티브로 전파
    return true;
};

account-svc 의 notification dispatch(reverse P/Invoke)에서 실행되므로, 구독자 핸들러가 던진 예외가 네이티브 프레임을 관통 → 프로세스 크래시. 또한 CheckAccountFeature() 는 등록 시점에 이미 통과한 검사를 매 notification 마다 네이티브 feature 조회로 반복합니다 (콜백 내 throw 경로이기도 함). (#7798, #7805 와 동일 계열)

(b) CreateAccountSubscriber(out s_subscriberHandle) 반환값 미검증 (line 653) — 생성 실패 시 invalid handle 로 RegisterSubscriber 진행.

(c) remove 접근자가 UnregisterSubscriber 실패 시 throw (line 674-678) — 이벤트 구독 해제 접근자는 throw 하지 않는 것이 .NET 가이드라인이며, throw 시 s_subscriberHandle 정리가 건너뛰어져 이후 상태 불일치.

(d) 정적 이벤트 add/remove 무동기화 — 두 스레드가 동시에 최초 구독하면 s_accountUpdated == null 을 둘 다 관찰 → RegisterSubscriber 이중 호출 경합.

관련: SafeAccountSubscriberHandle.ReleaseHandle (Interop.AccountService.cs:113-117) 은 네이티브 해제 없이 SetHandle(Zero) 만 수행 — Unregister 없이 방치된 구독자 핸들은 네이티브 측에서 누수.

Problem

  • Coding Guidelines 렌즈: 콜백 경계 예외 전파 금지 위반(크래시), 이벤트 접근자 계약 위반, 반환값 미검증, thread-safety 부재.
  • Performance 렌즈: notification 1건당 불필요한 native feature 조회 1회.

Proposed Improvement

private static readonly object s_subscriberLock = new object();

private static readonly Interop.AccountService.SubscribeCallback s_accountUpdatedCallback =
    (string eventType, int accountId, IntPtr userData) =>
{
    try
    {
        s_accountUpdated?.Invoke(null, new AccountSubscriberEventArgs(eventType, accountId));
    }
    catch (Exception e)
    {
        Log.Error(AccountErrorFactory.LogTag, $"Unhandled exception in AccountUpdated handler: {e}");
    }
    return true;
};

// add: lock(s_subscriberLock) 내에서 CreateAccountSubscriber 반환값 검증 후 RegisterSubscriber
// remove: lock 내 해제, Unregister 실패는 Log.Error 후 핸들 정리 (throw 제거)

Target Files

  • src/Tizen.Account.AccountManager/Tizen.Account.AccountManager/AccountService.cs
  • src/Tizen.Account.AccountManager/Interop/Interop.AccountService.cs

Expected Impact (Quantitative Metrics)

  • 구독자 예외 발 프로세스 크래시 경로: 1 → 0
  • notification 당 native feature 조회: 1회 → 0회
  • 최초 구독 경합 시 이중 RegisterSubscriber 경로: 차단
  • 미검증 네이티브 반환값: 2곳 → 0 (Create/Unregister)

API Compatibility Check

  • Public API signature change: 없음
  • Behavior change: 구독자 예외 시 크래시 → 로그 (catch 불가능한 크래시의 정상화), remove 실패 시 throw → 로그 (가이드라인 준수)
  • Tizen API Level floor: 유지

Impact Scope

  • 수정 지점: AccountService.cs 이벤트 영역 + Interop 핸들 클래스, 동일 어셈블리 내부 (rg 측정 2파일)
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