Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unnecessary process.args/env coping when spawning a child? #45868

Closed
ywave620 opened this issue Dec 15, 2022 · 2 comments
Closed

Unnecessary process.args/env coping when spawning a child? #45868

ywave620 opened this issue Dec 15, 2022 · 2 comments

Comments

@ywave620
Copy link
Contributor

The following TODO arouses my interest. Why we need to deep copy args and env to heap? The parent can not access or even modify the copy of them in the child once uv_spawn succeed, in case it failed, libuv does not(and has no reason) to touch them.

Code to prepare uv_process_options_t before call uv_spawn() in the implementation of child_process.spawn :

node/src/process_wrap.cc

Lines 178 to 204 in b3f5a41

// TODO(bnoordhuis) is this possible to do without mallocing ?
// options.file
Local<Value> file_v =
js_options->Get(context, env->file_string()).ToLocalChecked();
CHECK(file_v->IsString());
node::Utf8Value file(env->isolate(), file_v);
options.file = *file;
// options.args
Local<Value> argv_v =
js_options->Get(context, env->args_string()).ToLocalChecked();
if (!argv_v.IsEmpty() && argv_v->IsArray()) {
Local<Array> js_argv = argv_v.As<Array>();
int argc = js_argv->Length();
CHECK_GT(argc + 1, 0); // Check for overflow.
// Heap allocate to detect errors. +1 is for nullptr.
options.args = new char*[argc + 1];
for (int i = 0; i < argc; i++) {
node::Utf8Value arg(env->isolate(),
js_argv->Get(context, i).ToLocalChecked());
options.args[i] = strdup(*arg);
CHECK_NOT_NULL(options.args[i]);
}
options.args[argc] = nullptr;
}

Code to prepare uv_process_options_t before call uv_spawn() in the implementation of child_process.spawnSync :

node/src/spawn_sync.cc

Lines 755 to 765 in b3f5a41

Local<Value> js_file =
js_options->Get(context, env()->file_string()).ToLocalChecked();
if (!CopyJsString(js_file, &file_buffer_).To(&r)) return Nothing<int>();
if (r < 0) return Just(r);
uv_process_options_.file = file_buffer_;
Local<Value> js_args =
js_options->Get(context, env()->args_string()).ToLocalChecked();
if (!CopyJsStringArray(js_args, &args_buffer_).To(&r)) return Nothing<int>();
if (r < 0) return Just(r);
uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);

@ywave620 ywave620 changed the title Unnecessary process.args/env coping when spawning child? Unnecessary process.args/env coping when spawning a child? Dec 15, 2022
@bnoordhuis
Copy link
Member

Libuv's uv_spawn() (and the underlying execve() system call) expects the arguments and environment as a char*[] with a nullptr sentinel, that's why.

The code has changed over the years but the comment persisted. Maybe it should just be removed.

Something I noticed in the surrounding code:

CHECK_GT(argc + 1, 0);  // Check for overflow.

I think that's trying to check that argc != INT_MAX but the way it's written is UB.

bnoordhuis added a commit to bnoordhuis/io.js that referenced this issue Dec 16, 2022
bnoordhuis added a commit to bnoordhuis/io.js that referenced this issue Dec 16, 2022
@ywave620
Copy link
Contributor Author

@bnoordhuis Thanks for the information. The code makes sense to me now :)

nodejs-github-bot pushed a commit that referenced this issue Dec 20, 2022
Refs: #45868
PR-URL: #45882
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
targos pushed a commit that referenced this issue Jan 1, 2023
Refs: #45868
PR-URL: #45882
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
RafaelGSS pushed a commit that referenced this issue Jan 4, 2023
Refs: #45868
PR-URL: #45882
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
RafaelGSS pushed a commit that referenced this issue Jan 5, 2023
Refs: #45868
PR-URL: #45882
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
juanarbol pushed a commit that referenced this issue Jan 26, 2023
Refs: #45868
PR-URL: #45882
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
juanarbol pushed a commit that referenced this issue Jan 31, 2023
Refs: #45868
PR-URL: #45882
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Santiago Gimeno <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Mohammed Keyvanzadeh <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants