Node process hangs during `import('process')` if a sibling process reads from `stdin` and `stdin` is piped to a parent process
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- JavaScript
- Sterne
- 122k
- Forks
- 37.3k
- Ø Merge
- 4 T. 2 Std.
- Gemergte PRs (30 T.)
- 283
Beschreibung
Version
All versions, tested on v12 through v23.6.0
Platform
Windows 10 and 11
What steps will reproduce the bug?
Launching a process tree like the following causes grandchild2 to hang (cannot attach Node inspector, no JS code executes) after calling import('process') (which never resolves, unless its sibling grandchild1 exits):
main.js - launches child with piped stdin
middle.js - launches children with inherited stdin
grandchild1.js - attaches a listener to stdin
(1s later) grandchild2.js - imports node:process and then hangs
Example code:
main.js
require('child_process').spawn('node', ['middle.js'], { stdio: ['pipe', 'inherit', 'inherit'] });
middle.js
const { spawn } = require('child_process');
spawn('node', ['grandchild1.js'], { stdio: 'inherit' });
// Note: this also works: spawn('cmd', ['/c', 'pause'], { stdio: 'inherit' });
setTimeout(function () {
spawn('node', ['grandchild2.js'], { stdio: 'inherit' });
}, 1000);
grandchild1.js
process.stdin.on('data', console.log);
grandchild2.js
import('process').then(function (mod) {
console.log('import(node:process) completed'); // this line is never executed
});
console.log(process.pid, `grandchild2 started - if you don't see "not stuck" below, it's stuck`);
setInterval(function () {
console.log(process.pid, 'not stuck');
}, 1000);
Example repo with the above code (plus a bit more logging): https://github.com/Jimbly/node-stdin-hang-bug-demo
Tested on (all fail):
- Node v12...v22
- Windows 10, 11
Works fine on Linux, MacOS, presumably all non-Windows platforms.
How often does it reproduce? Is there a required condition?
Always (on Windows).
Additional information
Hang does not occur if any of these happen:
grandchild1is launched beforegrandchild2middle'sstdinis notpiped tomaingrandchild1's orgrandchild2'sstdinis notinheritgrandchild1exits (causesgrandchild2to get unstuck)
Hang still occurs if:
grandchild1is anything that reads from stdio (e.g.cmd /c pause)
The hung process's (native) call stack is:
NtSetInformationFile()
SetNamedPipeHandleState(pipeHandle, PIPE_READMODE_BYTE | PIPE_WAIT)
node.exe!uv__set_pipe_handle(loop=0x00007ff71d27f130, handle=0x000001c0c83367f0, pipeHandle=0x0000000000000278, fd=-1, duplex_flags=49152)
at deps\uv\src\win\pipe.c(482)
node.exe!uv_pipe_open(pipe=0x000001c0c83367f0, file=0)
at deps\uv\src\win\pipe.c(2480)
node.exe!node::PipeWrap::Open(args={...})
at src\pipe_wrap.cc(209)
node.exe!Builtins_CallApiCallbackGeneric()
at out\Release\obj\v8_snapshot\embedded.S(4265)
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_InterpreterPushArgsThenFastConstructFunction()
at out\Release\obj\v8_snapshot\embedded.S(4038)
node.exe!Builtins_ConstructHandler()
at out\Release\obj\v8_snapshot\embedded.S(56237)
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_GetPropertyWithReceiver()
at out\Release\obj\v8_snapshot\embedded.S(24522)
node.exe!Builtins_ReflectGet()
at out\Release\obj\v8_snapshot\embedded.S(41510)
00007ff69938aaf7()
00007ff69938acf4()
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_JSEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3658)
node.exe!Builtins_JSEntry()
at out\Release\obj\v8_snapshot\embedded.S(3616)
[Inline Frame] node.exe!v8::internal::GeneratedCode<unsigned __int64,unsigned __int64,unsigned __int64,unsigned __int64,unsigned __int64,__int64,unsigned __int64 * *>::Call()
at deps\v8\src\execution\simulator.h(178)
node.exe!v8::internal::`anonymous namespace'::Invoke(isolate=0x000001c0c82c1000, params={...})
at deps\v8\src\execution\execution.cc(420)
node.exe!v8::internal::Execution::Call(isolate=0x000001c0c82c1000, callable, receiver, argc=0, argv=0x0000000000000000)
at deps\v8\src\execution\execution.cc(506)
node.exe!v8::Function::Call(context, recv={...}, argc=0, argv=0x0000000000000000)
at deps\v8\src\api\api.cc(5484)
node.exe!node::loader::ModuleWrap::SyntheticModuleEvaluationStepsCallback(context={...}, module)
at src\module_wrap.cc(948)
node.exe!v8::internal::SyntheticModule::Evaluate(isolate=0x000001c0c82c1000, module={...})
at deps\v8\src\objects\synthetic-module.cc(108)
node.exe!v8::internal::Module::Evaluate(isolate=0x000001c0c82c1000, module={...})
at deps\v8\src\objects\module.cc(284)
node.exe!v8::Module::Evaluate(context)
at deps\v8\src\api\api.cc(2461)
[Inline Frame] node.exe!node::loader::ModuleWrap::Evaluate::__l2::<lambda_1>::operator()()
at src\module_wrap.cc(562)
node.exe!node::loader::ModuleWrap::Evaluate(args={...})
at src\module_wrap.cc(578)
node.exe!Builtins_CallApiCallbackGeneric()
at out\Release\obj\v8_snapshot\embedded.S(4265)
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_InterpreterEntryTrampoline()
at out\Release\obj\v8_snapshot\embedded.S(3946)
node.exe!Builtins_AsyncFunctionAwaitResolveClosure()
at out\Release\obj\v8_snapshot\embedded.S(11765)
node.exe!Builtins_PromiseFulfillReactionJob()
at out\Release\obj\v8_snapshot\embedded.S(40771)
node.exe!Builtins_RunMicrotasks()
at out\Release\obj\v8_snapshot\embedded.S(9703)
(truncated for size, see above repo if more stack is useful)
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Führe zuerst die verlinkte node-stdin-hang-bug-demo-Reproduktion unter Windows aus. Verfolge dann die Interaktion durch deps/uv/src/win/pipe.c, src/pipe_wrap.cc und src/module_wrap.cc, wobei der gemeldete native Stack als Ausgangspunkt dient. Als erledigt gilt die Aufgabe, wenn das entsprechende stdin-Szenario nicht mehr hängt und import('process') abgeschlossen wird, während sich die Reproduktion weiterhin korrekt verhält.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- javascript, node.js
- Bereich
- operating-systems
- Issue-Typ
- Bug
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Ruhig
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 35/100