Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/node_options-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,36 @@ void OptionsParser<Options>::Parse(

value = args.pop_first();

if (!value.empty() && value[0] == '-') {
bool is_eval_expression = false;
if (name == "--eval" && !value.empty() && value[0] == '-') {
std::string eval_value_name = value;
const size_t equals_index = value.find('=');
if (equals_index != std::string::npos) {
eval_value_name = value.substr(0, equals_index);
}

bool is_option_name =
options_.contains(eval_value_name) ||
aliases_.contains(eval_value_name) ||
aliases_.contains(eval_value_name + "=") ||
aliases_.contains(eval_value_name + " <arg>");

if (!is_option_name && eval_value_name.starts_with("--no-")) {
const std::string non_negated_name =
"--" + eval_value_name.substr(5);
is_option_name =
options_.contains(non_negated_name) ||
aliases_.contains(non_negated_name) ||
aliases_.contains(non_negated_name + "=") ||
aliases_.contains(non_negated_name + " <arg>");
}

is_eval_expression = !is_option_name;
}

if (!value.empty() &&
value[0] == '-' &&
!is_eval_expression) {
missing_argument();
break;
} else {
Expand Down
33 changes: 33 additions & 0 deletions test/parallel/test-cli-eval.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,39 @@ child.exec(...common.escapePOSIXShell`"${process.execPath}" -p "\\-42"`, common.
assert.strictEqual(stderr, '');
}));

// Unary-negative eval expressions should not be rejected as missing arguments.
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -42`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '-42\n');
assert.strictEqual(stderr, '');
}));

// Edge case: negative zero should preserve its sign when printed.
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -0`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, '-0\n');
assert.strictEqual(stderr, '');
}));

// Expressions like -NaN should be treated as eval input, not options.
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -NaN`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, 'NaN\n');
assert.strictEqual(stderr, '');
}));

// A bare '-' should be passed to eval and fail with a syntax error.
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -`, common.mustCall((err, stdout, stderr) => {
assert.notStrictEqual(err.code, 9);
assert.strictEqual(stdout, '');
assert.match(stderr, /SyntaxError/);
}));

// Nearby-path safety: option-looking values should still be rejected.
child.exec(...common.escapePOSIXShell`"${process.execPath}" -e -p`, common.mustCall((err, stdout, stderr) => {
assert.strictEqual(err.code, 9);
assert.strictEqual(stdout, '');
assert.strictEqual(stderr.trim(),
`${process.execPath}: -e requires an argument`);
}));

// Long output should not be truncated.
child.exec(...common.escapePOSIXShell`"${process.execPath}" -p "'1'.repeat(1e5)"`, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, `${'1'.repeat(1e5)}\n`);
Expand Down
Loading