70a0baaa59
mjsunit/regress/regress-crbug-9161 had two spinlocks on an atomic: 1. WaitUntil(lock == kStageRunning) 2. WaitUntil(lock == kStageDone) But, in theory the worker updating the "lock" could progress all the way to kStageDone before the first loop manages to check the lock value again. We can make this more robust by checking: 1. WaitUntil(lock != kStageInit) 2. WaitUntil(lock == kStageDone) That way both loops check for _any_ state past the state they want to progress past. Bug: v8:11437 Change-Id: I5220e61070a305301c678928edb0925c04dae970 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3231339 Auto-Submit: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Shu-yu Guo <syg@chromium.org> Cr-Commit-Position: refs/heads/main@{#77460}
60 lines
1.6 KiB
JavaScript
60 lines
1.6 KiB
JavaScript
// Copyright 2019 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// This test is a reproduction of a crash that happens when a TypedArray
|
|
// backed by a SharedArrayBuffer is concurrently modified while sorting.
|
|
// Segfaults would need a long time to trigger in normal builds, so this
|
|
// reproduction is tailored to trigger on ASAN builds. On ASAN builds,
|
|
// out-of-bounds accesses while sorting would result in an immediate failure.
|
|
|
|
const lock = new Int32Array(new SharedArrayBuffer(4));
|
|
|
|
const kIterations = 5000;
|
|
const kLength = 2000;
|
|
|
|
const kStageIndex = 0;
|
|
const kStageInit = 0;
|
|
const kStageRunning = 1;
|
|
const kStageDone = 2;
|
|
|
|
Atomics.store(lock, kStageIndex, kStageInit);
|
|
|
|
function WaitUntil(funcOfValue) {
|
|
while (true) {
|
|
const value = Atomics.load(lock, kStageIndex);
|
|
if (funcOfValue(value)) break;
|
|
}
|
|
}
|
|
|
|
const workerScript = `
|
|
onmessage = function([sab, lock]) {
|
|
const i32a = new Int32Array(sab);
|
|
Atomics.store(lock, ${kStageIndex}, ${kStageRunning});
|
|
|
|
for (let j = 1; j < ${kIterations}; ++j) {
|
|
for (let i = 0; i < i32a.length; ++i) {
|
|
i32a[i] = j;
|
|
}
|
|
}
|
|
|
|
postMessage("done");
|
|
Atomics.store(lock, ${kStageIndex}, ${kStageDone});
|
|
};`;
|
|
|
|
const worker = new Worker(workerScript, {type: 'string'});
|
|
|
|
const i32a = new Int32Array(
|
|
new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * kLength)
|
|
);
|
|
|
|
worker.postMessage([i32a.buffer, lock]);
|
|
WaitUntil(value => value !== kStageInit);
|
|
|
|
for (let i = 0; i < kIterations; ++i) {
|
|
i32a.sort();
|
|
}
|
|
|
|
WaitUntil(value => value === kStageDone);
|
|
assertEquals(worker.getMessage(), "done");
|