Skip to content

Crash: recursive os_unfair_lock in CFSocketInvalidate during mass socket teardown (VPN + airplane mode, 100% repro) #2306

Description

@octopurpie

Environment: Telegram iOS 12.9.3 (34622), iPhone 17 Pro (iPhone18,1), iOS 26.6.1 (23G83)

Steps to reproduce (100% for me):

  1. Connect any VPN (NEPacketTunnelProvider-based, tun keeps NWPath satisfied).
  2. Enable Airplane Mode. The app keeps trying to connect (path still looks
    satisfied through the tun interface), opening many parallel TCP connections
    to DCs (443/80/5222) that never complete.
  3. Wait ~4-5 minutes → app crashes in foreground.

Crash: EXC_BREAKPOINT — "BUG IN CLIENT OF LIBPLATFORM: Trying to
recursively lock an os_unfair_lock", faulting queue: GCDAsyncSocket.

Faulting thread:
_os_unfair_lock_recursive_abort
_os_unfair_lock_lock_slow
CFSocketInvalidate ← takes __CFAllSocketsLock
Schedulables::_SchedulablesInvalidateApplierFunction
CFArrayApplyFunction
SocketStream::~SocketStream() ← destructor re-enters
_CFRelease
CFSocketInvalidate ← same lock, recursive → abort
SocketStream::close
_CFStreamClose
MtProtoKitFramework (offsets 35960 / 52876 / 46652)
dispatch_source → GCDAsyncSocket queue

At crash time two more GCDAsyncSocket threads are blocked in
CFSocketInvalidate on the same lock, and another thread is inside
nw_endpoint_handler_path_change — i.e. concurrent CFStream teardown from
multiple queues during a network path change.

Root cause looks like a CF re-entrancy issue, but it is triggered by
MtProtoKit closing many CFStream-based sockets concurrently on path change.
Serializing stream close (or migrating those paths off CFStream/CFSocket)
would avoid it.

Full .ips attached.

ad1944bb-Telegram20260826230339.txt

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions