Skip to content

Use-after-free crash on Linux: URLSession _MultiHandle thread-safety bug #127

@KotlinFactory

Description

@KotlinFactory

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions