#558·quickjs

JS_PrintValue can read detached TypedArray storage after a reentrant write callback

Author: Sn0wyDayCreated Sep 12, 2026Updated Sep 12, 2026

JS_PrintValue() allows an embedder-supplied write callback. If that callback re-enters the same context and detaches the backing ArrayBuffer while a TypedArray is being printed, js_print_object() continues iterating with a cached count and reads the now-null data pointer.

On current master (04be246001599f5995fa2f2d8c91a0f198d3f34c), ASan/UBSan reports NULL + 1 followed by a read from address 0x1 on the second element. The current quickjs.c blob is the same e3716a4fa87f296f5486094fb29b516941ed9471 that was dynamically tested.

The trigger uses public APIs only:

  1. Create new Uint8Array([1, 2, 3]) and retain its backing buffer.
  2. Call JS_PrintValue() with an embedder write callback.
  3. When the callback receives the first element, call JS_DetachArrayBuffer() on that buffer.

The unmodified build aborts with:

quickjs.c:14072:57: runtime error: applying non-zero offset 1 to null pointer
quickjs.c:14077:21: runtime error: load of address 0x000000000001
ERROR: AddressSanitizer: SEGV on unknown address 0x000000000001

The problem is the cached len1 plus reading each element after output callbacks that may re-enter the VM. A tested fix rechecks the live count/data pointer at each iteration and copies the current element before calling the output callback. The same test then prints only the element read before detachment and returns without a sanitizer finding. The fix was checked with all 12 TypedArray classes and the regular make test suite.

This differs from #478: that issue involved constructor side effects creating an out-of-bounds TypedArray before printing. Here the TypedArray is initially valid and its buffer is detached by the JS_PrintValue() write callback after printing has started.

This is a conditional embedding-API crash. I did not find a path from the stock qjs CLI or ordinary JavaScript alone, and I am not claiming code execution or a CVE.

I can provide the complete C reproducer and tested patch if useful.

Disclosure: OpenAI Codex assisted with candidate triage, reproduction, and drafting. The runtime result, current source revision, regression suite, and impact limits were rechecked before submission.