From afb94ec7b3c9d7374ad693bf78fa58a54188f01e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 17 Jun 2023 09:01:02 +0200 Subject: [PATCH 1/2] src: support sync 'overlapped' stdio option Fix an oversight in the pull request that introduced the 'overlapped' option to the asynchronous child process methods, and also add it to the synchronous methods, like child_process.spawnSync(). Fixes: https://github.com/nodejs/node/issues/48476 Refs: https://github.com/nodejs/node/pull/29412 --- src/spawn_sync.cc | 22 ++++++++++++++++--- src/spawn_sync.h | 4 ++++ .../test-child-process-stdio-overlapped.js | 11 ++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index d03803fe3abc5b..0ec081d02de076 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -96,10 +96,12 @@ void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) { SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler, bool readable, bool writable, + bool overlapped, uv_buf_t input_buffer) : process_handler_(process_handler), readable_(readable), writable_(writable), + overlapped_(overlapped), input_buffer_(input_buffer), first_output_buffer_(nullptr), @@ -203,6 +205,11 @@ bool SyncProcessStdioPipe::writable() const { } +bool SyncProcessStdioPipe::overlapped() const { + return overlapped_; +} + + uv_stdio_flags SyncProcessStdioPipe::uv_flags() const { unsigned int flags; @@ -211,6 +218,8 @@ uv_stdio_flags SyncProcessStdioPipe::uv_flags() const { flags |= UV_READABLE_PIPE; if (writable()) flags |= UV_WRITABLE_PIPE; + if (overlapped()) + flags |= UV_OVERLAPPED_PIPE; return static_cast(flags); } @@ -909,7 +918,8 @@ int SyncProcessRunner::ParseStdioOption(int child_fd, if (js_type->StrictEquals(env()->ignore_string())) { return AddStdioIgnore(child_fd); - } else if (js_type->StrictEquals(env()->pipe_string())) { + } else if (js_type->StrictEquals(env()->pipe_string()) || + js_type->StrictEquals(env()->overlapped_string())) { Isolate* isolate = env()->isolate(); Local rs = env()->readable_string(); Local ws = env()->writable_string(); @@ -936,7 +946,8 @@ int SyncProcessRunner::ParseStdioOption(int child_fd, } } - return AddStdioPipe(child_fd, readable, writable, buf); + bool overlapped = js_type->StrictEquals(env()->overlapped_string()); + return AddStdioPipe(child_fd, readable, writable, overlapped, buf); } else if (js_type->StrictEquals(env()->inherit_string()) || js_type->StrictEquals(env()->fd_string())) { @@ -963,12 +974,17 @@ int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) { int SyncProcessRunner::AddStdioPipe(uint32_t child_fd, bool readable, bool writable, + bool overlapped, uv_buf_t input_buffer) { CHECK_LT(child_fd, stdio_count_); CHECK(!stdio_pipes_[child_fd]); std::unique_ptr h( - new SyncProcessStdioPipe(this, readable, writable, input_buffer)); + new SyncProcessStdioPipe(this, + readable, + writable, + overlapped, + input_buffer)); int r = h->Initialize(uv_loop_); if (r < 0) { diff --git a/src/spawn_sync.h b/src/spawn_sync.h index d5b74e67d83094..928c5fc6633469 100644 --- a/src/spawn_sync.h +++ b/src/spawn_sync.h @@ -75,6 +75,7 @@ class SyncProcessStdioPipe { SyncProcessStdioPipe(SyncProcessRunner* process_handler, bool readable, bool writable, + bool overlapped, uv_buf_t input_buffer); ~SyncProcessStdioPipe(); @@ -86,6 +87,7 @@ class SyncProcessStdioPipe { inline bool readable() const; inline bool writable() const; + inline bool overlapped() const; inline uv_stdio_flags uv_flags() const; inline uv_pipe_t* uv_pipe() const; @@ -118,6 +120,7 @@ class SyncProcessStdioPipe { bool readable_; bool writable_; + bool overlapped_; uv_buf_t input_buffer_; SyncProcessOutputBuffer* first_output_buffer_; @@ -182,6 +185,7 @@ class SyncProcessRunner { inline int AddStdioPipe(uint32_t child_fd, bool readable, bool writable, + bool overlapped, uv_buf_t input_buffer); inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd); diff --git a/test/parallel/test-child-process-stdio-overlapped.js b/test/parallel/test-child-process-stdio-overlapped.js index 5c48e7ee105792..4cefbc570b28c6 100644 --- a/test/parallel/test-child-process-stdio-overlapped.js +++ b/test/parallel/test-child-process-stdio-overlapped.js @@ -37,6 +37,17 @@ if (!require('fs').existsSync(exePath)) { common.skip(exe + ' binary is not available'); } +// We can't synchronously write to the child (the 'input' and 'stdio' options +// conflict) but we can at least verify it starts up normally and is then +// terminated by the timer watchdog. +const { error } = child_process.spawnSync(exePath, [], { + stdio: ['overlapped', 'pipe', 'pipe'], + timeout: 42, +}); + +assert.ok(error); +assert.strictEqual(error.code, 'ETIMEDOUT'); + const child = child_process.spawn(exePath, [], { stdio: ['overlapped', 'pipe', 'pipe'] }); From 65aab5eac28b2f70f4169f37cb8f2b8daa1d8ec1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 17 Jun 2023 09:15:46 +0200 Subject: [PATCH 2/2] squash! shut up linter --- src/spawn_sync.cc | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index 0ec081d02de076..5dbacef9593c01 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -92,7 +92,6 @@ void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) { next_ = next; } - SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler, bool readable, bool writable, @@ -115,7 +114,6 @@ SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler, CHECK(readable || writable); } - SyncProcessStdioPipe::~SyncProcessStdioPipe() { CHECK(lifecycle_ == kUninitialized || lifecycle_ == kClosed); @@ -204,12 +202,10 @@ bool SyncProcessStdioPipe::writable() const { return writable_; } - bool SyncProcessStdioPipe::overlapped() const { return overlapped_; } - uv_stdio_flags SyncProcessStdioPipe::uv_flags() const { unsigned int flags; @@ -218,8 +214,7 @@ uv_stdio_flags SyncProcessStdioPipe::uv_flags() const { flags |= UV_READABLE_PIPE; if (writable()) flags |= UV_WRITABLE_PIPE; - if (overlapped()) - flags |= UV_OVERLAPPED_PIPE; + if (overlapped()) flags |= UV_OVERLAPPED_PIPE; return static_cast(flags); } @@ -970,7 +965,6 @@ int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) { return 0; } - int SyncProcessRunner::AddStdioPipe(uint32_t child_fd, bool readable, bool writable, @@ -979,12 +973,8 @@ int SyncProcessRunner::AddStdioPipe(uint32_t child_fd, CHECK_LT(child_fd, stdio_count_); CHECK(!stdio_pipes_[child_fd]); - std::unique_ptr h( - new SyncProcessStdioPipe(this, - readable, - writable, - overlapped, - input_buffer)); + std::unique_ptr h(new SyncProcessStdioPipe( + this, readable, writable, overlapped, input_buffer)); int r = h->Initialize(uv_loop_); if (r < 0) { @@ -1000,7 +990,6 @@ int SyncProcessRunner::AddStdioPipe(uint32_t child_fd, return 0; } - int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) { CHECK_LT(child_fd, stdio_count_); CHECK(!stdio_pipes_[child_fd]);