Source code

Revision control

Copy as Markdown

Other Tools

// |jit-test| slow
var moduleText = `(module
(type $i16arr (array (mut i16)))
(func $fromCharCodeArray
(import "wasm:js-string" "fromCharCodeArray")
(param (ref null $i16arr) i32 i32)
(result (ref extern)))
(func (export "makeArr")
(param $len i32) (param $val i32) (result (ref $i16arr))
(array.new $i16arr (local.get $val) (local.get $len))
)
(func (export "arrToStr")
(param $arr (ref null $i16arr)) (param $start i32) (param $end i32)
(result externref)
(call $fromCharCodeArray (local.get $arr)
(local.get $start) (local.get $end))
)
)`;
var inst = wasmEvalText(moduleText, {}, {builtins: ['js-string']});
// Set nursery to 4MB for multi-chunk mode (ChunkSize = 1MB).
// After minor GC, chunks 1-3 get ASAN MakeNoAccess poisoning.
gcparam("minNurseryBytes", 4 * 1024 * 1024);
gcparam("maxNurseryBytes", 4 * 1024 * 1024);
gcparam("semispaceNurseryEnabled", 0);
// Array: 80 i16 elements -> storageBytes = 168 bytes (8 header + 160 data).
// This is OOL (exceeds WasmArrayObject_MaxInlineBytes ~96-112) but within
// MaxNurseryTrailerSize (256), so buffer is nursery-allocated.
// Value: 0x100 (non-Latin1) forces char16_t string (no deflation to Latin1).
var ARRAY_ELEMS = 80;
// Substring length 10: fits JSThinInlineString for char16_t (max ~12 chars).
// The inline path allocates the cell first (can GC), then PodCopy from source.
var STR_LEN = 10;
gc();
// Tight loop: each iteration uses ~256 bytes of nursery.
// With 4MB nursery, fills after ~16000 iterations.
// When the nursery fills, there's a window where array+buffer fit in nursery
// but the string cell allocation overflows it:
// NoGC fails -> CanGC fallback with stale StableWasmArrayObjectElements ->
// minor GC moves buffer -> PodCopy reads from stale pointer -> UAF.
for (var i = 0; i < 50000; i++) {
var arr = inst.exports.makeArr(ARRAY_ELEMS, 0x45); // 0x45 == 'E'
// If we're picking up poisoned data from the old nursery, then either
// arrToStr should (C++)-assert, or if it doesn't, the assertEq below should
// fail.
let str = inst.exports.arrToStr(arr, 0, STR_LEN);
assertEq(str, "EEEEEEEEEE");
}