Skip to content

Upgrade bellard/quickjs to 2026-06-04#266

Open
xnacly wants to merge 6 commits into
justjake:mainfrom
xnacly:update-quickjs-2026-06-04
Open

Upgrade bellard/quickjs to 2026-06-04#266
xnacly wants to merge 6 commits into
justjake:mainfrom
xnacly:update-quickjs-2026-06-04

Conversation

@xnacly

@xnacly xnacly commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Upgrades the vendored bellard/quickjs from
2025-09-13+f1139494
to 2026-06-04+04be2460

Because the 2026-06-04 release is ~30% faster on bench-v8 and adds a bunch
of language features, see QuickJS
changelog
.

Regressions i found and had to fix

  1. getOwnPropertyNames heap corruption**: QTS_GetOwnPropertyNames
    allocated its output array with the system malloc(), but the JS side frees it
    with QTS_FreeVoidPointer -> js_free. QuickJS's new allocator is not
    malloc-compatible (js_free expects a block header), so this mismatch
    corrupted the heap. Fixed by allocating with js_malloc to match the free.

  2. setMemoryLimit is inaccurate: the new allocator over-commits memory in
    whole-arena chunks, making JS_SetMemoryLimit enforcement coarse and
    unreliable. Fixed by falling back to the host malloc() under __EMSCRIPTEN__
    (JS_MALLOC_LARGE_BLOCKS_ONLY), exactly as its already done. Added as a
    vendored patch.

xnacly added 6 commits July 22, 2026 15:04
04be246 run-test262: when updating errors, sort them so that it gives the same result with several threads
42d08be optimized Array.prototype.slice and Array.prototype.splice
762e6fc fixed typo in commit 445624b
088cf5e inlined the float case in relational operators
8f0c037 use JSValueConst arguments for js_strict_eq2()
445624b inlined more cases for equality operators
3d5e064 new release
ccfe076 Check return values of fallible functions (#518)
8b04550 Add fuzz targets for ES6 modules, JSON, RegExp, and bytecode (#512)
cfc846a doc update
ad1e7bd keep more generic cpu_count() for non Linux systems
92a3d4d fixed microbench with d8
8e97f24 faster add, sub and mul for mixed integer floating point operands
594f965 exclude few very slow and currently useless test262 tests
10c81b1 fixed large performance regression with recent GCC versions
e2c01df add optional define to add asm labels for each opcode to ease code inspection and profiling
2504823 added multi-threading support in run-test262 (initial patch by bnoordhuis) - fixed unsafe thread termination in show_progress() - use the number of physical cores by default - added -T option to force the number of threads - avoid hardcoding the maximum number of threads
458992e removed CONFIG_AGENT
774e30e fixed win32 compilation
f838177 ArrayBuffer.prototype.transfer: avoid destroying the old array buffer in case the allocation of the new array buffer fails. Also avoid setting opaque = NULL for the custom array buffer free function
14a1536 add line number info in variable initialization (#458)
ecd05ea use the host malloc() for all allocations when ASAN is enabled
4a13c45 fixed setuid() / setgid() ordering (#517)
e6c2be8 disable inlining of malloc() wrappers to avoid problems with LTO (#515)
163b9b7 added poll() support so that the number of file handles is not limited (#502)
8a3aaa1 Add run-test262 --no-can-block flag (#505)
d73189d fixed compilation with clang
99e9181 added custom malloc for small blocks (11% faster on bench-v8)
e182e3d Add Uint8Array base64/hex methods (initial patch by saghul)
1f50b39 memcpy() (currently) has undefined behavior if a pointer is NULL with zero size (#500)
b1b4733 fixed error handling in os.exec() (#503)
c1ba371 added missing NULL pointer check (#504)
9b90125 use __EMSCRIPTEN__ define instead of EMSCRIPTEN
efda450 fixed (again) JS atomics in case of typed array resizing - use same function name as quickjs-ng for js_atomics_get_buf() (#508)
d417caf added libunicode unicode version (#509)
6b62098 Merge pull request #496 from bptato/fix-hex-access
8e09295 Merge pull request #495 from nickva/fix-initializer-string-warning
66afb72 Fix member access on non-decimal numeric literals
d38eea9 Avoid initializer-string warning for the digits array
d7ae12a added JSON.parse source text access
a31dcef added basic protection against too large function in serialized bytecode
5022f2b fixed use-after-free via re-entrant GC in FinalizationRegistry weak reference cleanup (#494)
e7b9f21 Fix async generator lifecycle bug (bnoordhuis) (quickjs-ng/quickjs#1355)
4d16546 fixed RegExp.escape
46bd985 fixed buffer overflow in Atomics with resizable typed arrays
16d6947 typo
f1b63fc Fix memory leak in Iterator.prototype.map (saghul) (#493)
841dd03 fixed buffer overflow in TypedArray.prototype.with (#492)
69090b9 Fix stack underflow with generator in iterable (saghul) (#488)
aaf0174 test262 update
68caa5f fixed TypedArray constructor semantics which removes a buffer overflow (#478)
0989d4c fixed TypedArray sort semantics by copying the array before calling the comparison function. Fixed buffer overflow when the array is resized (#477)
4c722ce modified js_allocate_fast_array() so that the array is fully initialized. It is slightly slower but avoids several nasty bugs (#471)

git-subtree-dir: vendor/quickjs
git-subtree-split: 04be246001599f5995fa2f2d8c91a0f198d3f34c
QTS_GetOwnPropertyNames allocated its output array with the system malloc()
but the JS side frees it via QTS_FreeVoidPointer -> js_free. QuickJS 2026-06-04
introduced a custom small-block allocator whose js_free is not malloc-compatible,
so this mismatch corrupted the heap (leaked objects, memory access out of bounds,
and abort() during GC). Allocate with js_malloc to match the free.
QuickJS 2026-06-04's new small-block arena allocator over-commits memory in
whole-arena chunks, making JS_SetMemoryLimit enforcement coarse and inaccurate.
Fall back to the host malloc() under __EMSCRIPTEN__ (JS_MALLOC_LARGE_BLOCKS_ONLY),
the same as the AddressSanitizer build already does. Recorded as a vendored patch.
@xnacly
xnacly force-pushed the update-quickjs-2026-06-04 branch from 0769c1a to 62ae207 Compare July 22, 2026 15:09
Comment thread c/interface.c
Comment on lines +929 to +931
// Must use js_malloc (not malloc): the JS side frees this array via
// QTS_FreeVoidPointer -> js_free. Mixing malloc with js_free corrupts the
// heap under QuickJS's custom small-block allocator (2026-06-04+).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need lore comments

#define JS_MALLOC_MAX_SMALL_SIZE 512
-#if defined(__SANITIZE_ADDRESS__)
-/* use the host malloc() for all allocations */
+#if defined(__SANITIZE_ADDRESS__) || defined(__EMSCRIPTEN__)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we disable the new performance optimization, then we don't get the claimed speedup, right?

Comment thread CHANGELOG.md
Comment on lines +11 to +13
- Upgrade [bellard/quickjs](https://github.com/bellard/quickjs) to [2026-06-04+04be2460](https://github.com/bellard/quickjs/commit/04be246001599f5995fa2f2d8c91a0f198d3f34c). This release is ~30% faster on bench-v8 thanks to micro-optimizations and a new custom small-block allocator, and adds resizable `ArrayBuffer`s, `ArrayBuffer.prototype.transfer`, the `Iterator` helpers, `Set` methods, `Map`/`WeakMap.prototype.upsert`, `Math.sumPrecise`, `Uint8Array` base64/hex methods, and RegExp duplicate named groups. Review the [QuickJS changelog](https://github.com/bellard/quickjs/blob/04be246001599f5995fa2f2d8c91a0f198d3f34c/Changelog) for details. Two Emscripten-specific regressions were found and fixed as part of this upgrade:
- Fixed heap corruption in `getOwnPropertyNames`: the FFI allocated the result array with the system `malloc` but freed it with QuickJS's `js_free`. The new small-block allocator is not `malloc`-compatible, so this mismatch corrupted the heap (manifesting as leaked objects, `memory access out of bounds`, and `abort()` during GC). Now allocated with `js_malloc` to match.
- Disabled QuickJS's new custom small-block allocator under Emscripten (`JS_MALLOC_LARGE_BLOCKS_ONLY`, as the AddressSanitizer build already does). The arena allocator over-commits memory in whole-arena chunks, which made `RuntimeOptions.memoryLimit` / `setMemoryLimit` enforcement inaccurate.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please follow the existing format, and place in a new section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants