镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

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

Description

@ywave620

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_);

Activity

  1. changed the title [-]Unnecessary process.args/env coping when spawning child?[/-] [+]Unnecessary process.args/env coping when spawning a child?[/+] on Dec 15, 2022
  2. bnoordhuis commented on Dec 16, 2022

    @bnoordhuis
    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.

  3. ywave620 commented on Dec 16, 2022

    @ywave620
    ContributorAuthor

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

  4. added a commit that references this issue on Jan 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions