mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
The one-character strings of U+0080..U+07FF that string iteration shares between threads were allocated from the calling thread's memory. On Linux a worker that exits without sharing anything returns that memory, so the table kept strings that a later read found discarded. They now come from the system allocator, as other state that outlives a thread does.
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
/* The one-character strings that string iteration shares between threads
|
|
* outlive the worker that first made them. On Linux a worker that exits
|
|
* without sharing anything returns its memory; with SCR_SA_DISCARD=poison
|
|
* that memory becomes inaccessible instead, so a cached character
|
|
* allocated from the worker's memory would fault when the main thread
|
|
* reads it. The corpus program pins Node.js parity; this suite runs it
|
|
* with the discard poisoned and immediate. Under SCRIPTC_SAN=1 the runtime
|
|
* keeps every worker's memory, so the check does not apply. */
|
|
import { execFile } from "node:child_process";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { expect, test } from "vitest";
|
|
import { compile } from "@scriptc/compiler";
|
|
|
|
const exec = promisify(execFile);
|
|
const program = join(import.meta.dirname, "../corpus/8348-string-iteration-worker-characters.ts");
|
|
const sanitize = process.env["SCRIPTC_SAN"] === "1";
|
|
|
|
test.skipIf(process.platform !== "linux" || sanitize)(
|
|
"characters a discarded worker cached stay readable",
|
|
{ timeout: 240_000 },
|
|
async () => {
|
|
const outDir = await mkdtemp(join(tmpdir(), "scriptc-string-iteration-workers-"));
|
|
try {
|
|
const result = await compile(program, {
|
|
backend: "llvm",
|
|
outDir,
|
|
outPath: join(outDir, "program"),
|
|
});
|
|
expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true);
|
|
if (!result.ok) return;
|
|
const { stdout } = await exec(result.binaryPath, [], {
|
|
env: { ...process.env, SCR_SA_DISCARD: "poison", SCR_SA_DISCARD_DELAY_MS: "0" },
|
|
timeout: 120_000,
|
|
});
|
|
expect(stdout).toContain("main 1:61 1:e9 1:20 1:f1");
|
|
expect(stdout).toContain("spread a|é| |ñ");
|
|
} finally {
|
|
await rm(outDir, { recursive: true, force: true });
|
|
}
|
|
},
|
|
);
|