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

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions