Skip to content

Upgrade embedded Bun to fix concurrent bun:ffi TinyCC segfaults #13954

Open

Description

@marius-kilocode

Description

Kilo CLI 7.5.16 embeds Bun 1.3.14. On macOS arm64, restoring a session can intermittently crash the standalone CLI with a segmentation fault in Bun's TinyCC-backed bun:ffi wrapper compiler:

Bun v1.3.14 (0d9b296a)
Segmentation fault at address 0x0000006C

tccpp.c:3789: tccpp_new
tccpp.c:3703: preprocess_start
libtcc.c:825: tcc_compile
tcc.zig:224: TCC.State.compileString
ffi.zig:1571: FFI.Function.compile
ffi.zig:1124: FFI.open

The original report was observed on macOS 26.5.2, Apple Silicon, after approximately 60 seconds while running kilo -s <session-id>.

Steps to Reproduce

The exact user's session restore has not been reproduced in a synthetic session. The underlying Bun defect is reproducible independently of Kilo and OpenTUI:

  1. Use the official Bun 1.3.14 arm64 standalone binary.
  2. Start 12 fresh Workers at the same time.
  3. Release a barrier so every Worker calls bun:ffi.dlopen() for /usr/lib/libSystem.B.dylib simultaneously.
  4. Repeat the process.

Observed results with the official Bun 1.3.14 binary:

  • Cold concurrent FFI initialization: 2 failures in 50 runs in the final reproduction.
  • A separate 100-run series produced 2 failures.
  • One failure generated the same low-address 0x6C fault.
  • One failure generated a macOS allocator error consistent with concurrent parser-state cleanup.
  • One main-thread FFI prewarm followed by the same Worker barrier: 0 failures in 50 runs.
  • Bun 1.4.2 with the same cold barrier: 0 failures in 50 runs.

The reproduction uses only bun:ffi and a system library. It does not require OpenTUI, FFF, plugins, or shared Worker state.

Root Cause

Bun 1.3.14 uses TinyCC to compile regular bun:ffi wrappers. TinyCC has process-global parser and code-generation state and protects it with a process-global semaphore.

The macOS semaphore initialization is not thread-safe:

if (!p->init)
    p->sem = dispatch_semaphore_create(1), p->init = 1;

Two first callers can both observe an uninitialized semaphore, create different semaphore objects, and enter the compiler concurrently. TinyCC's shared parser tables then become corrupted.

The 0x6C fault maps to a corrupted TokenSym pointer. The crashing instruction reads the len field at offset 0x2c through a pointer containing 0x40:

0x40 + 0x2c = 0x6c

This is a TinyCC/Bun runtime defect, not an ARM64 ABI, dynamic-loader, OpenTUI, FFF, or Kilo session-data problem.

Relevant Versions

  • Affected embedded runtime: Bun 1.3.14 (0d9b296af)
  • Affected Kilo release: CLI 7.5.16
  • Tested fixed runtime: Bun 1.4.2
  • Current Bun release at investigation time: Bun 1.4.2
  • Bun engine-native FFI implementation: PR oven-sh/bun#35246, merged as 01b81aa4003b375c53fd22eb0fc4de592ac892e0
  • Matching upstream report: oven-sh/bun#40972

Bun 1.4 moves dlopen(), linkSymbols(), CFunction(), and JSCallback() to JavaScriptCore's native FFI path. TinyCC remains for cc() only, so the failing regular FFI path is removed.

Proposed Solution

Update the Bun runtime used to build and embed the Kilo CLI to Bun 1.4.2 or newer.

Do not add an application-level FFF/OpenTUI preload workaround. The confirmed defect is in Bun's first concurrent FFI initialization, and the runtime upgrade fixes the general path rather than relying on a particular library load order.

Validation Requirements

  • Update packageManager, Bun types, lockfile, and release/build metadata as required.
  • Keep the known-safe splitting: false setting unless the release matrix proves it can be changed safely.
  • Build all normal and baseline release targets.
  • Run the macOS arm64 standalone smoke tests.
  • Verify Linux x64 baseline TUI startup, because Bun 1.4.0 previously produced a blank artifact.
  • Repeat the 12-Worker FFI barrier test on the embedded runtime.
  • Run the focused CLI, TUI worker, and PTY checks.

Related Work

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

    CLIKilo Code CLIbugSomething isn't workingdependenciesPull requests that update a dependency file

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions