Skip to content

Commit 2086d8c

Browse files
committed
cli: allow unary-negated eval arguments
Fixes: #43397 Signed-off-by: jorge guerrero <grrr.jrg@gmail.com>
1 parent 13eb80f commit 2086d8c

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

src/node_options-inl.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,36 @@ void OptionsParser<Options>::Parse(
467467

468468
value = args.pop_first();
469469

470-
if (!value.empty() && value[0] == '-') {
470+
bool is_eval_expression = false;
471+
if (name == "--eval" && !value.empty() && value[0] == '-') {
472+
std::string eval_value_name = value;
473+
const size_t equals_index = value.find('=');
474+
if (equals_index != std::string::npos) {
475+
eval_value_name = value.substr(0, equals_index);
476+
}
477+
478+
bool is_option_name =
479+
options_.contains(eval_value_name) ||
480+
aliases_.contains(eval_value_name) ||
481+
aliases_.contains(eval_value_name + "=") ||
482+
aliases_.contains(eval_value_name + " <arg>");
483+
484+
if (!is_option_name && eval_value_name.starts_with("--no-")) {
485+
const std::string non_negated_name =
486+
"--" + eval_value_name.substr(5);
487+
is_option_name =
488+
options_.contains(non_negated_name) ||
489+
aliases_.contains(non_negated_name) ||
490+
aliases_.contains(non_negated_name + "=") ||
491+
aliases_.contains(non_negated_name + " <arg>");
492+
}
493+
494+
is_eval_expression = !is_option_name;
495+
}
496+
497+
if (!value.empty() &&
498+
value[0] == '-' &&
499+
!is_eval_expression) {
471500
missing_argument();
472501
break;
473502
} else {

test/parallel/test-cli-eval.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,39 @@ child.exec(...common.escapePOSIXShell`"${process.execPath}" -p "\\-42"`, common.
115115
assert.strictEqual(stderr, '');
116116
}));
117117

118+
// Unary-negative eval expressions should not be rejected as missing arguments.
119+
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -42`, common.mustSucceed((stdout, stderr) => {
120+
assert.strictEqual(stdout, '-42\n');
121+
assert.strictEqual(stderr, '');
122+
}));
123+
124+
// Edge case: negative zero should preserve its sign when printed.
125+
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -0`, common.mustSucceed((stdout, stderr) => {
126+
assert.strictEqual(stdout, '-0\n');
127+
assert.strictEqual(stderr, '');
128+
}));
129+
130+
// Expressions like -NaN should be treated as eval input, not options.
131+
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -NaN`, common.mustSucceed((stdout, stderr) => {
132+
assert.strictEqual(stdout, 'NaN\n');
133+
assert.strictEqual(stderr, '');
134+
}));
135+
136+
// A bare '-' should be passed to eval and fail with a syntax error.
137+
child.exec(...common.escapePOSIXShell`"${process.execPath}" -pe -`, common.mustCall((err, stdout, stderr) => {
138+
assert.notStrictEqual(err.code, 9);
139+
assert.strictEqual(stdout, '');
140+
assert.match(stderr, /SyntaxError/);
141+
}));
142+
143+
// Nearby-path safety: option-looking values should still be rejected.
144+
child.exec(...common.escapePOSIXShell`"${process.execPath}" -e -p`, common.mustCall((err, stdout, stderr) => {
145+
assert.strictEqual(err.code, 9);
146+
assert.strictEqual(stdout, '');
147+
assert.strictEqual(stderr.trim(),
148+
`${process.execPath}: -e requires an argument`);
149+
}));
150+
118151
// Long output should not be truncated.
119152
child.exec(...common.escapePOSIXShell`"${process.execPath}" -p "'1'.repeat(1e5)"`, common.mustSucceed((stdout, stderr) => {
120153
assert.strictEqual(stdout, `${'1'.repeat(1e5)}\n`);

0 commit comments

Comments
 (0)