Skip to content

Compiled binary: Workers leak extracted native .so/.dylib files in /tmp (never cleaned up) #29585

@wuyang630

Description

@wuyang630

Summary

When a Bun-compiled binary uses new Worker(), each Worker instance extracts embedded native modules (.so/.dylib files) to /tmp with unique hash-based filenames. These files are never cleaned up after the Worker is terminated, causing unbounded disk growth.

Reproduction

Setup

A compiled binary that:

  1. Embeds a native library loaded via bun:ffi dlopen() (e.g., @opentui/core uses import("./libopentui.so", { with: { type: "file" } }) then dlopen())
  2. Creates Workers that trigger the native module loading path

Steps

# Build a compiled binary
bun build --compile --entrypoints ./index.ts --outfile ./myapp

# Run the binary - it spawns Workers for file operations
./myapp serve

Observed behavior

  • Each new Worker() call extracts the embedded native .so/.dylib to /tmp with a unique hash filename (e.g., .5ffbafXXX-00000000.so)
  • When worker.terminate() is called, the extracted file remains in /tmp
  • Subsequent Worker creations extract new copies with different hashes instead of reusing existing ones
  • Files are hidden (dot-prefixed), so ls does not show them, but ls -a / find does

Measured impact (real-world: opencode serve)

  • File size: ~4.3 MB each (Linux x64) / ~860 KB each (macOS arm64)
  • Creation rate: ~9 files per 10 seconds when actively processing requests
  • Leak rate: ~14 GB/hour on Linux
  • Disk fill time: fills a 300 GB / partition in ~19 hours

Verification

# Monitor growth
watch -n 5 "find /tmp -maxdepth 1 -name '.*-00000000.so' -type f | wc -l"

# Identify the files
file /tmp/.5ffbaf*-00000000.so
# Output: ELF 64-bit LSB shared object, x86-64

nm -gU /tmp/.5ffbaf*-00000000.so | head -5
# Shows symbols from the embedded native library (e.g., opentui renderer)

Expected behavior

  • Extracted native files should be reused across Worker instances (content-hash based deduplication)
  • OR extracted files should be cleaned up when the Worker is terminated
  • OR at minimum, a single extraction per unique module should be shared via the existing $bunfs mechanism

Environment

  • Bun: v1.x compiled binary mode (bun build --compile)
  • OS: Linux x64 (primary), also reproduced on macOS arm64
  • Native loading: bun:ffi dlopen() on a file imported with { with: { type: "file" } }

Workaround

Periodic cleanup via cron:

*/30 * * * * find /tmp -maxdepth 1 -name ".*-00000000.so" -mmin +5 -delete

Context

Discovered while running opencode in serve mode on a production server. The @opentui/core library embeds a platform-specific .so via bun:ffi, and opencode creates/destroys ripgrep Workers frequently for file search operations. Each Worker extraction leaks the native module to /tmp.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions