Skip to content

Fix strict name conformity cases #335

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

Merged
merged 2 commits into from
Mar 30, 2024
Merged
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
24 changes: 21 additions & 3 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -31466,6 +31466,25 @@ static __exception int js_parse_directives(JSParseState *s)
return js_parse_seek_token(s, &pos);
}

static BOOL js_invalid_strict_name(JSAtom name) {
switch (name) {
case JS_ATOM_eval:
case JS_ATOM_arguments:
case JS_ATOM_implements: // future strict reserved words
case JS_ATOM_interface:
case JS_ATOM_let:
case JS_ATOM_package:
case JS_ATOM_private:
case JS_ATOM_protected:
case JS_ATOM_public:
case JS_ATOM_static:
case JS_ATOM_yield:
return TRUE;
default:
return FALSE;
}
}

static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
JSAtom func_name)
{
Expand All @@ -31476,13 +31495,12 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
if (!fd->has_simple_parameter_list && fd->has_use_strict) {
return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
}
if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) {
if (js_invalid_strict_name(func_name)) {
return js_parse_error(s, "invalid function name in strict code");
}
for (idx = 0; idx < fd->arg_count; idx++) {
name = fd->args[idx].var_name;

if (name == JS_ATOM_eval || name == JS_ATOM_arguments) {
if (js_invalid_strict_name(name)) {
return js_parse_error(s, "invalid argument name in strict code");
}
}
Expand Down
70 changes: 64 additions & 6 deletions tests/test_language.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,25 @@ function assert(actual, expected, message) {
&& actual.toString() === expected.toString())
return;

var msg = message ? " (" + message + ")" : "";
throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
", expected |" + expected + "|" + msg);
}

function assert_throws(expected_error, func)
function assert_throws(expected_error, func, message)
{
var err = false;
var msg = message ? " (" + message + ")" : "";
try {
func();
} catch(e) {
err = true;
if (!(e instanceof expected_error)) {
throw Error("unexpected exception type");
throw Error(`expected ${expected_error.name}, got ${e.name}${msg}`);
}
}
if (!err) {
throw Error("expected exception");
throw Error(`expected ${expected_error.name}${msg}`);
}
}

Expand Down Expand Up @@ -421,7 +422,9 @@ function test_argument_scope()
var c = "global";

f = function(a = eval("var arguments")) {};
assert_throws(SyntaxError, f);
// for some reason v8 does not throw an exception here
if (typeof require === 'undefined')
assert_throws(SyntaxError, f);

f = function(a = eval("1"), b = arguments[0]) { return b; };
assert(f(12), 12);
Expand Down Expand Up @@ -536,6 +539,60 @@ function test_function_expr_name()
assert_throws(TypeError, f);
}

function test_expr(expr, err) {
if (err)
assert_throws(err, () => eval(expr), `for ${expr}`);
else
assert(1, eval(expr), `for ${expr}`);
}

function test_name(name, err)
{
test_expr(`(function() { return typeof ${name} ? 1 : 1; })()`);
test_expr(`(function() { var ${name}; ${name} = 1; return ${name}; })()`);
test_expr(`(function() { let ${name}; ${name} = 1; return ${name}; })()`, name == 'let' ? SyntaxError : undefined);
test_expr(`(function() { const ${name} = 1; return ${name}; })()`, name == 'let' ? SyntaxError : undefined);
test_expr(`(function(${name}) { ${name} = 1; return ${name}; })()`);
test_expr(`(function({${name}}) { ${name} = 1; return ${name}; })({})`);
test_expr(`(function ${name}() { return ${name} ? 1 : 0; })()`);
test_expr(`"use strict"; (function() { return typeof ${name} ? 1 : 1; })()`, err);
test_expr(`"use strict"; (function() { if (0) ${name} = 1; return 1; })()`, err);
test_expr(`"use strict"; (function() { var x; if (0) x = ${name}; return 1; })()`, err);
test_expr(`"use strict"; (function() { var ${name}; return 1; })()`, err);
test_expr(`"use strict"; (function() { let ${name}; return 1; })()`, err);
test_expr(`"use strict"; (function() { const ${name} = 1; return 1; })()`, err);
test_expr(`"use strict"; (function() { var ${name}; ${name} = 1; return 1; })()`, err);
test_expr(`"use strict"; (function() { var ${name}; ${name} = 1; return ${name}; })()`, err);
test_expr(`"use strict"; (function(${name}) { return 1; })()`, err);
test_expr(`"use strict"; (function({${name}}) { return 1; })({})`, err);
test_expr(`"use strict"; (function ${name}() { return 1; })()`, err);
test_expr(`(function() { "use strict"; return typeof ${name} ? 1 : 1; })()`, err);
test_expr(`(function() { "use strict"; if (0) ${name} = 1; return 1; })()`, err);
test_expr(`(function() { "use strict"; var x; if (0) x = ${name}; return 1; })()`, err);
test_expr(`(function() { "use strict"; var ${name}; return 1; })()`, err);
test_expr(`(function() { "use strict"; let ${name}; return 1; })()`, err);
test_expr(`(function() { "use strict"; const ${name} = 1; return 1; })()`, err);
test_expr(`(function() { "use strict"; var ${name}; ${name} = 1; return 1; })()`, err);
test_expr(`(function() { "use strict"; var ${name}; ${name} = 1; return ${name}; })()`, err);
test_expr(`(function(${name}) { "use strict"; return 1; })()`, err);
test_expr(`(function({${name}}) { "use strict"; return 1; })({})`, SyntaxError);
test_expr(`(function ${name}() { "use strict"; return 1; })()`, err);
}

function test_reserved_names()
{
test_name('await');
test_name('yield', SyntaxError);
test_name('implements', SyntaxError);
test_name('interface', SyntaxError);
test_name('let', SyntaxError);
test_name('package', SyntaxError);
test_name('private', SyntaxError);
test_name('protected', SyntaxError);
test_name('public', SyntaxError);
test_name('static', SyntaxError);
}

test_op1();
test_cvt();
test_eq();
Expand All @@ -555,3 +612,4 @@ test_spread();
test_function_length();
test_argument_scope();
test_function_expr_name();
test_reserved_names();
54 changes: 0 additions & 54 deletions v8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -779,60 +779,6 @@ Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Failure: expected <null> found <undefined>
Failure: expected <undefined> found <function non_strict() {
return return_my_caller();
Expand Down