Fix strict name conformity cases (#335)

- reject *future strict reserved words* in `js_parse_function_check_names()`.
- add tests for reserved names in tests/test_language.js
- allow running tests/test_language.js with v8
- update v8.txt
This commit is contained in:
Charlie Gordon 2024-03-30 17:15:25 +01:00 committed by GitHub
parent 8b56215cc2
commit 0de570988a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 85 additions and 63 deletions

View file

@ -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)
{
@ -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");
}
}

View file

@ -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}`);
}
}
@ -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);
@ -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();
@ -555,3 +612,4 @@ test_spread();
test_function_length();
test_argument_scope();
test_function_expr_name();
test_reserved_names();

54
v8.txt
View file

@ -711,60 +711,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();