-
Notifications
You must be signed in to change notification settings - Fork 56
Description
Summary
Concurrent LLM requests crash on Linux with a use-after-free in libFoundationNetworking's URLSession._MultiHandle. This is a known thread-safety bug in swift-corelibs-foundation's libcurl-backed URLSession, and it affects AnyLanguageModel because all model implementations use URLSession for HTTP.
Crash Log
Object 0x71467803b120 of class _MultiHandle deallocated with non-zero retain count 2.
This object's deinit, or something called from it, may have created a strong reference
to self which outlived deinit, resulting in a dangling reference.
💣 Program crashed: Bad pointer dereference at 0x000071412c7a405c
Thread 41 "NIO-SGLTN-1-#7" crashed:
0 _swift_release_dealloc + 13 in libswiftCore.so
1 doDecrementSlow + 366 in libswiftCore.so
2 specialized _NativeDictionary.copy() + 318 in libFoundationNetworking.so
3 specialized Dictionary._Variant.removeValue(forKey:) + 106 in libFoundationNetworking.so
4 URLSession._MultiHandle.endOperation(for:) + 55 in libFoundationNetworking.so
Environment
- Platform: x86_64 Linux (Debian 13 trixie)
- Swift 6.2
- AnyLanguageModel 0.6.x
Root Cause
Each model type (Gemini, OpenAI, Anthropic, Ollama) creates its own URLSession(configuration: .default). On Linux, URLSession is backed by libFoundationNetworking which wraps libcurl via a _MultiHandle singleton. When multiple model calls execute concurrently, _MultiHandle.endOperation(for:) corrupts its internal dictionary — a known race condition in swift-corelibs-foundation.
The Linux streaming path in URLSession+Extensions.swift makes it worse by creating an additional URLSession per streaming request (line ~195):
let session = URLSession(
configuration: self.configuration,
delegate: delegate,
delegateQueue: delegateQueue
)Suggested Fix
Replace URLSession with AsyncHTTPClient (NIO-based, no libcurl dependency). This is the standard HTTP client in the Swift on Server ecosystem and doesn't suffer from _MultiHandle issues.
Alternatively, a shared singleton URLSession with serialized access would reduce (but not fully eliminate) the race window.
Workaround
Serializing all LLM calls so only one URLSession request is in flight at a time avoids the crash, but at the cost of throughput.