mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
fix(javascript): require exactly one fork IPC channel (#8017)
* fix(javascript): require exactly one fork IPC channel
Node's fork() rejects an explicit stdio array that carries more than one IPC
channel, and the throw is synchronous, before any child process exists:
if (ArrayPrototypeFilter(options.stdio, ...'ipc').length > 1)
throw new ERR_IPC_ONE_PIPE()
The analysis already dropped an array with no "ipc" (#7992) but still reported a
resolved fork for an array carrying it twice.
Measured on Node 24.22.1:
fork({stdio: ["ipc", "ipc"]}) -> THROWS ERR_IPC_ONE_PIPE
fork({stdio: ["pipe", "ipc", "ipc"]}) -> THROWS ERR_IPC_ONE_PIPE
fork({stdio: ["ipc"]}) -> SPAWNED connected=true
fork({stdio: ["pipe", "ipc"]}) -> SPAWNED connected=true
fork({stdio: ["pipe", "pipe", "pipe", "ipc"]})-> SPAWNED connected=true
So the required count is exactly one, not at least one. Count the resolved "ipc"
literals and reject the candidate unless the count is one; a spread or an
unreadable element may still change the count and is left alone, as before.
* chore: retrigger title and readiness checks after the title was corrected
This commit is contained in:
1 parent
f8ec48095a
commit
007e181f68
2 files changed
+22
-8
No files matched your search
@@ -37,6 +37,18 @@ it.each([
|
||||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* Exactly one channel is required: naming `"ipc"` twice throws ERR_IPC_ONE_PIPE
|
||||
* for the same synchronous reason, so those calls are not spawns either.
|
||||
*/
|
||||
it.each([
|
||||
["ipc twice", `["ipc", "ipc"]`],
|
||||
["three ipc entries", `["ipc", "ipc", "ipc"]`],
|
||||
["a pipe between two ipc entries", `["pipe", "ipc", "ipc"]`],
|
||||
] as const)("emits no fork for a stdio array with %s", (_name, stdio) => {
|
||||
expect(spawnsFor(`fork("worker.js", { stdio: ${stdio} })`)).toEqual([]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["a string stdio", `fork("worker.js", { stdio: "pipe" })`],
|
||||
["omitted stdio", `fork("worker.js", {})`],
|
||||
|
||||
@@ -450,12 +450,13 @@ const stdioMode = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Node's `fork` requires an explicit `stdio` array to carry the IPC channel. An
|
||||
* array that provably omits `"ipc"` throws ERR_CHILD_PROCESS_IPC_REQUIRED
|
||||
* synchronously, before any child process exists, so it is not a spawn at all.
|
||||
* A string `stdio` is normalised with `"ipc"` appended, so only the array form
|
||||
* can omit it; a spread or unreadable element may still supply the channel and
|
||||
* is therefore left alone.
|
||||
* Node's `fork` requires an explicit `stdio` array to carry exactly one IPC
|
||||
* channel. An array that provably omits `"ipc"` throws
|
||||
* ERR_CHILD_PROCESS_IPC_REQUIRED, and one that names `"ipc"` twice throws
|
||||
* ERR_IPC_ONE_PIPE; both throws are synchronous, before any child process
|
||||
* exists, so such a call is not a spawn at all. A string `stdio` is normalised
|
||||
* with a single `"ipc"` appended, so only the array form can be wrong; a spread
|
||||
* or unreadable element may still change the count and is therefore left alone.
|
||||
*/
|
||||
const forkRejectsStdioArray = (
|
||||
candidate: SpawnCandidate,
|
||||
@@ -477,10 +478,11 @@ const forkRejectsStdioArray = (
|
||||
);
|
||||
if (literals.some((literal) => literal === undefined || !literal.found))
|
||||
return false;
|
||||
return !literals.some(
|
||||
const ipcCount = literals.filter(
|
||||
(literal) =>
|
||||
literal !== undefined && literal.found && literal.value === "ipc",
|
||||
);
|
||||
).length;
|
||||
return ipcCount !== 1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user