Commit 3828ce0c authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[class] Ban arguments in class field initializers

Create a new function kind for initializer functions and ban arguments
if used in such a function.

Bug: v8:5367, v8:7183
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: Id3089e587b3d6a25f27224045f250e032b831818
Reviewed-on: https://chromium-review.googlesource.com/850547
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50369}
parent b822d3e1
......@@ -1437,6 +1437,10 @@ bool Scope::NeedsScopeInfo() const {
return NeedsContext();
}
bool Scope::ShouldBanArguments() {
return GetReceiverScope()->should_ban_arguments();
}
DeclarationScope* Scope::GetReceiverScope() {
Scope* scope = this;
while (!scope->is_script_scope() &&
......
......@@ -396,6 +396,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
return static_cast<Variable*>(variables_.Start()->value);
}
bool ShouldBanArguments();
// ---------------------------------------------------------------------------
// Variable allocation.
......@@ -696,6 +698,10 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
bool asm_module() const { return asm_module_; }
void set_asm_module();
bool should_ban_arguments() const {
return IsClassFieldsInitializerFunction(function_kind());
}
void DeclareThis(AstValueFactory* ast_value_factory);
void DeclareArguments(AstValueFactory* ast_value_factory);
void DeclareDefaultFunctionVariables(AstValueFactory* ast_value_factory);
......
......@@ -1095,7 +1095,6 @@ enum FunctionKind : uint16_t {
kArrowFunction = 1 << 0,
kGeneratorFunction = 1 << 1,
kConciseMethod = 1 << 2,
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod,
kDefaultConstructor = 1 << 3,
kDerivedConstructor = 1 << 4,
kBaseConstructor = 1 << 5,
......@@ -1103,6 +1102,10 @@ enum FunctionKind : uint16_t {
kSetterFunction = 1 << 7,
kAsyncFunction = 1 << 8,
kModule = 1 << 9,
kClassFieldsInitializerFunction = 1 << 10 | kConciseMethod,
kLastFunctionKind = kClassFieldsInitializerFunction,
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod,
kAccessorFunction = kGetterFunction | kSetterFunction,
kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
kDefaultDerivedConstructor = kDefaultConstructor | kDerivedConstructor,
......@@ -1134,7 +1137,8 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
kind == FunctionKind::kAsyncArrowFunction ||
kind == FunctionKind::kAsyncConciseMethod ||
kind == FunctionKind::kAsyncConciseGeneratorMethod ||
kind == FunctionKind::kAsyncGeneratorFunction;
kind == FunctionKind::kAsyncGeneratorFunction ||
kind == FunctionKind::kClassFieldsInitializerFunction;
}
......@@ -1212,6 +1216,11 @@ inline bool IsClassConstructor(FunctionKind kind) {
return (kind & FunctionKind::kClassConstructor) != 0;
}
inline bool IsClassFieldsInitializerFunction(FunctionKind kind) {
DCHECK(IsValidFunctionKind(kind));
return kind == FunctionKind::kClassFieldsInitializerFunction;
}
inline bool IsConstructable(FunctionKind kind) {
if (IsAccessorFunction(kind)) return false;
if (IsConciseMethod(kind)) return false;
......
......@@ -267,6 +267,8 @@ class ErrorUtils : public AllStatic {
T(ApplyNonFunction, \
"Function.prototype.apply was called on %, which is a % and not a " \
"function") \
T(ArgumentsDisallowedInInitializer, \
"'arguments' is not allowed in class field initializer") \
T(ArrayBufferTooShort, \
"Derived ArrayBuffer constructor created a buffer which was too small") \
T(ArrayBufferSpeciesThis, \
......
......@@ -307,12 +307,14 @@ class ScopeInfo : public FixedArray {
class HasSimpleParametersField
: public BitField<bool, AsmModuleField::kNext, 1> {};
class FunctionKindField
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 10> {};
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 11> {};
class HasOuterScopeInfoField
: public BitField<bool, FunctionKindField::kNext, 1> {};
class IsDebugEvaluateScopeField
: public BitField<bool, HasOuterScopeInfoField::kNext, 1> {};
STATIC_ASSERT(kLastFunctionKind <= FunctionKindField::kMax);
// Properties of variables.
class VariableModeField : public BitField<VariableMode, 0, 3> {};
class InitFlagField : public BitField<InitializationFlag, 3, 1> {};
......
......@@ -469,7 +469,7 @@ class SharedFunctionInfo : public HeapObject {
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(IsWrappedBit, bool, 1, _) \
V(FunctionKindBits, FunctionKind, 10, _) \
V(FunctionKindBits, FunctionKind, 11, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
......@@ -486,6 +486,7 @@ class SharedFunctionInfo : public HeapObject {
STATIC_ASSERT(BailoutReason::kLastErrorMessage <=
DisabledOptimizationReasonBits::kMax);
STATIC_ASSERT(kLastFunctionKind <= FunctionKindBits::kMax);
// Masks for checking if certain FunctionKind bits are set without fully
// decoding of the FunctionKind bit field.
static const int kClassConstructorMask = FunctionKind::kClassConstructor
......
......@@ -1663,6 +1663,13 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
if (next == Token::IDENTIFIER || next == Token::ASYNC ||
(next == Token::AWAIT && !parsing_module_ && !is_async_function())) {
IdentifierT name = impl()->GetSymbol();
if (impl()->IsArguments(name) && scope()->ShouldBanArguments()) {
ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer);
*ok = false;
return impl()->NullIdentifier();
}
// When this function is used to read a formal parameter, we don't always
// know whether the function is going to be strict or sloppy. Indeed for
// arrow functions we don't always know that the identifier we are reading
......@@ -2416,7 +2423,8 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info,
: class_info->instance_fields_scope;
if (initializer_scope == nullptr) {
initializer_scope = NewFunctionScope(FunctionKind::kConciseMethod);
initializer_scope =
NewFunctionScope(FunctionKind::kClassFieldsInitializerFunction);
// TODO(gsathya): Make scopes be non contiguous.
initializer_scope->set_start_position(scanner()->location().end_pos);
initializer_scope->SetLanguageMode(LanguageMode::kStrict);
......
......@@ -3339,6 +3339,8 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
FunctionLiteral* Parser::CreateInitializerFunction(
DeclarationScope* scope, ZoneList<ClassLiteral::Property*>* fields) {
DCHECK_EQ(scope->function_kind(),
FunctionKind::kClassFieldsInitializerFunction);
// function() { .. class fields initializer .. }
ZoneList<Statement*>* statements = NewStatementList(1);
InitializeClassFieldsStatement* static_fields =
......
......@@ -428,7 +428,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(18),
B(LdaConstant), U8(16),
B(Star), R(19),
......
......@@ -143,7 +143,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -432,7 +432,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -743,7 +743,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -991,7 +991,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......
......@@ -86,7 +86,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -227,7 +227,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -380,7 +380,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -523,7 +523,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(10),
B(LdaConstant), U8(10),
B(Star), R(11),
......
......@@ -90,7 +90,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(13),
B(LdaConstant), U8(7),
B(Star), R(14),
......@@ -268,7 +268,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(13),
B(LdaConstant), U8(11),
B(Star), R(14),
......@@ -422,7 +422,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(11),
B(LdaConstant), U8(9),
B(Star), R(12),
......@@ -524,7 +524,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(73),
B(LdaSmi), I8(74),
B(Star), R(17),
B(LdaConstant), U8(4),
B(Star), R(18),
......@@ -580,7 +580,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(16),
B(LdaConstant), U8(9),
B(Star), R(17),
......@@ -754,7 +754,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......@@ -953,7 +953,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(15),
B(LdaConstant), U8(14),
B(Star), R(16),
......@@ -1116,7 +1116,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(20),
B(LdaConstant), U8(7),
B(Star), R(21),
......@@ -1358,7 +1358,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(20),
B(LdaConstant), U8(9),
B(Star), R(21),
......
......@@ -257,7 +257,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(143),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(14),
B(LdaConstant), U8(15),
B(Star), R(15),
......
......@@ -231,7 +231,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(73),
B(LdaSmi), I8(74),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
......
......@@ -4751,6 +4751,9 @@ TEST(StaticClassFieldsNoErrors) {
"static ['a']\n *b(){}",
"static ['a']\n ['b'](){}",
"static a = function t() { arguments; }",
"static a = () => function t() { arguments; }",
// ASI edge cases
"static a\n get",
"static get\n *a(){}",
......@@ -4843,6 +4846,9 @@ TEST(ClassFieldsNoErrors) {
"get\n *a(){}",
"a\n static",
"a = function t() { arguments; }",
"a = () => function() { arguments; }",
// Misc edge cases
"yield",
"yield = 0",
......@@ -4891,6 +4897,14 @@ TEST(StaticClassFieldsErrors) {
"static async a = 0",
"static async a",
"static a = arguments",
"static a = () => arguments",
"static a = () => { arguments }",
"static a = arguments[0]",
"static a = delete arguments[0]",
"static a = f(arguments)",
"static a = () => () => arguments",
// ASI requires a linebreak
"static a b",
"static a = 0 b",
......@@ -4931,6 +4945,14 @@ TEST(ClassFieldsErrors) {
"async a = 0",
"async a",
"a = arguments",
"a = () => arguments",
"a = () => { arguments }",
"a = arguments[0]",
"a = delete arguments[0]",
"a = f(arguments)",
"a = () => () => arguments",
// ASI requires a linebreak
"a b",
"a = 0 b",
......
......@@ -652,3 +652,47 @@ x()();
}
}, ReferenceError);
}
{
class X {
p = function() { return arguments[0]; }
}
let x = new X;
assertEquals(1, x.p(1));
}
{
class X {
t = () => {
function p() { return arguments[0]; };
return p;
}
}
let x = new X;
let p = x.t();
assertEquals(1, p(1));
}
{
class X {
t = () => {
function p() { return eval("arguments[0]"); };
return p;
}
}
let x = new X;
let p = x.t();
assertEquals(1, p(1));
}
{
class X {
p = eval("(function() { return arguments[0]; })(1)");
}
let x = new X;
assertEquals(1, x.p);
}
......@@ -416,3 +416,44 @@ y()();
assertEquals(1, obj.x);
assertEquals(2, klass.x);
}
{
class X {
static p = function() { return arguments[0]; }
}
assertEquals(1, X.p(1));
}
{
class X {
static t = () => {
function p() { return arguments[0]; };
return p;
}
}
let p = X.t();
assertEquals(1, p(1));
}
{
class X {
static t = () => {
function p() { return eval("arguments[0]"); };
return p;
}
}
let p = X.t();
assertEquals(1, p(1));
}
{
class X {
static p = eval("(function() { return arguments[0]; })(1)");
}
assertEquals(1, X.p);
}
/*---
description: Syntax error if `arguments` used in class field (arrow function expression)
esid: sec-class-definitions-static-semantics-early-errors
features: [class, class-fields-public, arrow-function]
flags: [generated]
negative:
phase: early
type: SyntaxError
info: |
Static Semantics: Early Errors
FieldDefinition:
PropertyNameInitializeropt
- It is a Syntax Error if ContainsArguments of Initializer is true.
Static Semantics: ContainsArguments
IdentifierReference : Identifier
1. If the StringValue of Identifier is "arguments", return true.
...
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false.
---*/
throw "Test262: This statement should not be evaluated.";
var C = class {
x = () => {
var t = () => { arguments; };
t();
}
}
/*---
description: error if `arguments` in StatementList of eval (direct eval)
esid: sec-performeval-rules-in-initializer
features: [class, class-fields-public, arrow-function]
flags: [generated]
info: |
Static Semantics: Early Errors
FieldDefinition:
PropertyNameInitializeropt
- It is a Syntax Error if ContainsArguments of Initializer is true.
Static Semantics: ContainsArguments
IdentifierReference : Identifier
1. If the StringValue of Identifier is "arguments", return true.
...
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false.
---*/
var C = class {
x = () => {
var t = () => { eval("arguments"); };
t();
}
}
assert.throws(SyntaxError, function() {
var c = new C();
c.x();
});
/*---
description: error if `arguments` in StatementList of eval (direct eval)
esid: sec-performeval-rules-in-initializer
features: [class, class-fields-public, arrow-function]
flags: [generated]
info: |
Static Semantics: Early Errors
FieldDefinition:
PropertyNameInitializeropt
- It is a Syntax Error if ContainsArguments of Initializer is true.
Static Semantics: ContainsArguments
IdentifierReference : Identifier
1. If the StringValue of Identifier is "arguments", return true.
...
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false.
---*/
var C = class {
x = eval("() => arguments");
}
assert.throws(SyntaxError, function() {
var c = new C();
c.x();
});
/*---
description: Syntax error if `arguments` used in class field (arrow function expression)
esid: sec-class-definitions-static-semantics-early-errors
features: [class, class-fields-public, arrow-function]
flags: [generated]
negative:
phase: early
type: SyntaxError
info: |
Static Semantics: Early Errors
FieldDefinition:
PropertyNameInitializeropt
- It is a Syntax Error if ContainsArguments of Initializer is true.
Static Semantics: ContainsArguments
IdentifierReference : Identifier
1. If the StringValue of Identifier is "arguments", return true.
...
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false.
---*/
throw "Test262: This statement should not be evaluated.";
class C {
x = () => {
var t = () => { arguments; };
t();
}
}
/*---
description: error if `arguments` in StatementList of eval (direct eval)
esid: sec-performeval-rules-in-initializer
features: [class, class-fields-public, arrow-function]
flags: [generated]
info: |
Static Semantics: Early Errors
FieldDefinition:
PropertyNameInitializeropt
- It is a Syntax Error if ContainsArguments of Initializer is true.
Static Semantics: ContainsArguments
IdentifierReference : Identifier
1. If the StringValue of Identifier is "arguments", return true.
...
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false.
---*/
class C {
x = () => {
var t = () => { eval("arguments"); };
t();
}
}
assert.throws(SyntaxError, function() {
var c = new C();
c.x();
});
/*---
description: error if `arguments` in StatementList of eval (direct eval)
esid: sec-performeval-rules-in-initializer
features: [class, class-fields-public, arrow-function]
flags: [generated]
info: |
Static Semantics: Early Errors
FieldDefinition:
PropertyNameInitializeropt
- It is a Syntax Error if ContainsArguments of Initializer is true.
Static Semantics: ContainsArguments
IdentifierReference : Identifier
1. If the StringValue of Identifier is "arguments", return true.
...
For all other grammatical productions, recurse on all nonterminals. If any piece returns true, then return true. Otherwise return false.
---*/
class C {
x = eval("() => arguments");
}
assert.throws(SyntaxError, function() {
var c = new C();
c.x();
});
......@@ -455,30 +455,6 @@
'built-ins/TypedArrays/BigInt64Array/*': [SKIP],
'built-ins/TypedArrays/BigUint64Array/*': [SKIP],
# https://bugs.chromium.org/p/v8/issues/detail?id=7183
'language/expressions/class/fields-arrow-fnc-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-comp-name-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-direct-eval-err-contains-arguments': [FAIL],
'language/expressions/class/fields-equality-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-literal-name-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-static-literal-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-static-string-literal-name-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-string-literal-name-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-ternary-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-typeof-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-arrow-fnc-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-direct-eval-err-contains-arguments': [FAIL],
'language/statements/class/fields-equality-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-literal-name-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-static-comp-name-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-static-literal-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-static-string-literal-name-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-string-literal-name-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-typeof-init-err-contains-arguments': [FAIL],
'language/expressions/class/fields-static-comp-name-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-ternary-init-err-contains-arguments': [FAIL],
'language/statements/class/fields-comp-name-init-err-contains-arguments': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7184
'annexB/language/expressions/yield/star-iterable-return-emulates-undefined-throws-when-called': [FAIL],
'annexB/language/statements/for-await-of/iterator-close-return-emulates-undefined-throws-when-called': [FAIL],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment