Skip to content

Bun.spawn stdin: new Response() heap corruption #26979

@jpdutoit

Description

@jpdutoit

How can we reproduce the crash?

Summary

Bun.spawn with stdin: new Response(data) causes heap corruption (segfault / pas panic) when concurrent Bun.file().exists() calls and another Bun.spawn stdout read are happening. 100% reproducible.

Environment

  • Bun 1.3.9, macOS arm64 (Apple Silicon)
  • Exit code 133 (SIGTRAP) or 139 (SIGSEGV)

Reproduction

Save as repro.ts and run with bun repro.ts. Couldn't reproduce on Replit/CodeAndbox so suspect it might be macOS only.

export {};

async function run() {
  const fileOps = Array.from({ length: 10 }, () => Bun.file("/tmp/nope").exists());

  const outer = Bun.spawn(["bash", "-c", 'for j in $(seq 1 100); do echo "padding padding padding"; done'], {
    stdout: "pipe",
    stderr: "pipe"
  });
  const outerText = new Response(outer.stdout as ReadableStream).text();

  const inner = Bun.spawn(["cat"], {
    stdin: new Response("x".repeat(20000)),
    stdout: "pipe"
  });
  await new Response(inner.stdout as ReadableStream).text();

  await inner.exited;
  await outerText;
  await outer.exited;
  await Promise.all(fileOps);
}

await run();
await run();
console.log("OK");

Crash rate: 100% (10/10 runs).

Crash output

Manifests as one of two forms depending on timing:

panic(main thread): Segmentation fault at address 0x11213BA080000
pas panic: deallocation did fail ... Alloc bit not set in pas_segregated_page_deallocate_with_page

Both are heap corruption — the first is a corrupted pointer dereference, the second is the allocator's assertion catching an invalid free.

Three required ingredients

All three must be concurrent. Removing any one prevents the crash:

Ingredient What Threshold
Bun.file().exists() Concurrent file existence checks >= 10 calls
Bun.spawn stdout Read via new Response(stdout).text() >= ~100 lines of output
Bun.spawn stdin stdin: new Response(data) data >= 11,757 bytes

What does NOT crash

  • stdin: "pipe" with manual .write() / .end()never crashes
  • stdin: "ignore" or stdin: "inherit"never crashes
  • Fewer than 10 concurrent Bun.file().exists() calls — never crashes
  • stdin: new Response() data smaller than 11,757 bytes — never crashes
  • Replacing Bun.file().exists() with setTimeout or other async work — never crashes
  • Two spawns without any Bun.file() calls — never crashes

Workaround

Write to a temp file instead of using stdin: new Response():

// CRASHES:
const proc = Bun.spawn(["dot", "-Tsvg"], {
  stdin: new Response(code),
  stdout: "pipe"
});

// WORKS:
const tmp = `/tmp/input-${Date.now()}.dot`;
await Bun.write(tmp, code);
const proc = Bun.spawn(["dot", "-Tsvg", tmp], {
  stdin: "ignore",
  stdout: "pipe"
});

Relevant log output

============================================================
Bun v1.3.9 (cf6cdbbb) macOS Silicon
macOS v15.7.3
CPU: fp aes crc32 atomics
Args: "bun" "run" "tests/repro.ts"
Features: jsc spawn(4) tsconfig
Builtins: "bun:main"
Elapsed: 18ms | User: 10ms | Sys: 7ms
RSS: 29.26MB | Peak: 29.26MB | Commit: 1.07GB | Faults: 51 | Machine: 51.54GB

panic(main thread): Segmentation fault at address 0x10F137A080000
oh no: Bun has crashed. This indicates a bug in Bun, not your code.

Stack Trace (bun.report)

Bun v1.3.9 (cf6cdbb) on macos aarch64 [AutoCommand]

Segmentation fault at address 0x10D12B6600010

  • 1 unknown/js code
  • Heap.cpp:2893: JSC::Heap::collectIfNecessaryOrDefer
  • Heap.cpp:2893: JSC::Heap::collectIfNecessaryOrDefer
  • LazyPropertyInlines.h:107: JSC::JSString* JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSString>::callFunc<Bun::MarkdownTagStrings::initialize()::$_7>
  • Assertions.h:977: operationPutByValDirectBeyondArrayBoundsStrict
  • 6 unknown/js code
  • JSGlobalObject.zig:553: bun.js.node.util.validators.throwErrInvalidArgTypeWithMessage
  • Vector.h:122: WTF::UniqueRef<JSC::ChainedWatchpoint>* WTF::Vector<WTF::UniqueRef<JSC::ChainedWatchpoint>, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>::expandCapacity<(...)0>
  • pair.h:467: WTF::HashTableIterator<WTF::HashTable<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::KeyValuePair<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > > >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashMap<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::HashTableTraits, (...)0, WTF::FastMalloc>::KeyValuePairTraits, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::FastMalloc>, std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::KeyValuePair<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > > >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashMap<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::HashTableTraits, (...)0, WTF::FastMalloc>::KeyValuePairTraits, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> > > WTF::HashTable<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::KeyValuePair<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > > >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashMap<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::HashTableTraits, (...)0, WTF::FastMalloc>::KeyValuePairTraits, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::FastMalloc>::find<WTF::IdentityHashTranslator<WTF::HashMap<std::__1::pair<JSC::Structure*, JSC::JSCell*>, WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> >, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<std::__1::pair<JSC::Structure*, JSC::JSCell*> >, WTF::HashTraits<WTF::RefPtr<JSC::StructureShape, WTF::RawPtrTraits<JSC::StructureShape>, WTF::DefaultRefDerefTraits<JSC::StructureShape> > >, WTF::HashTableTraits, (...)0, WTF::FastMalloc>::KeyValuePairTraits, WTF::DefaultHash<std::__1::pair<JSC::Structure*, JSC::JSCell*> > >, (...)0, std::__1::pair<JSC::Structure*, JSC::JSCell*> >
  • ZigGlobalObject.h:346: Zig::GlobalObject::GlobalObject
  • VirtualMachine.zig:2576: bun.js.VirtualMachine.printStackTrace
  • fs.zig:1681: Watcher.addFile
  • RuntimeTranspilerStore.zig:585: bun.js.RuntimeTranspilerStore.RuntimeTranspilerStore.TranspilerJob.runFromWorkerThread
  • immutable.zig:1060: array_hash_map.ArrayHashMapUnmanaged
  • segment.c:228: mi_segment_span_free_coalesce

Features: spawn, tsconfig, jsc

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions