mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
The constructor check should return false for arrow and generator functions (#4328)
The previous `ecma_is_constructor` implementation did not checked if the target function was an arrow or generator function. This resulted in an incorrect execution for these function types. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.usz@partner.samsung.com
This commit is contained in:
parent
cc52282f34
commit
3af3597f2e
@ -129,24 +129,25 @@ ecma_op_is_callable (ecma_value_t value) /**< ecma value */
|
||||
} /* ecma_op_is_callable */
|
||||
|
||||
/**
|
||||
* Checks whether the given object implements [[Construct]].
|
||||
* Implement IsConstructor abstract operation.
|
||||
*
|
||||
* @return true - if the given object is constructor;
|
||||
* false - otherwise
|
||||
*
|
||||
* @return ECMA_IS_VALID_CONSTRUCTOR - if object is a valid for constructor call
|
||||
* any other value - if object is not a valid constructor, the pointer contains the error message.
|
||||
*/
|
||||
inline bool JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */
|
||||
char *
|
||||
ecma_object_check_constructor (ecma_object_t *obj_p) /**< ecma object */
|
||||
{
|
||||
JERRY_ASSERT (!ecma_is_lexical_environment (obj_p));
|
||||
|
||||
ecma_object_type_t type = ecma_get_object_type (obj_p);
|
||||
|
||||
if (type < ECMA_OBJECT_TYPE_PROXY)
|
||||
if (JERRY_UNLIKELY (type < ECMA_OBJECT_TYPE_PROXY))
|
||||
{
|
||||
return false;
|
||||
return ECMA_ERR_MSG ("Invalid type for constructor call.");
|
||||
}
|
||||
|
||||
while (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
|
||||
while (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION))
|
||||
{
|
||||
ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) obj_p;
|
||||
|
||||
@ -156,20 +157,115 @@ ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */
|
||||
type = ecma_get_object_type (obj_p);
|
||||
}
|
||||
|
||||
if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION))
|
||||
{
|
||||
bool is_builtin = ecma_get_object_is_builtin (obj_p);
|
||||
|
||||
if (is_builtin)
|
||||
{
|
||||
if (ecma_builtin_function_is_routine (obj_p))
|
||||
{
|
||||
return ECMA_ERR_MSG ("Built-in routines are not constructors.");
|
||||
}
|
||||
|
||||
return ECMA_IS_VALID_CONSTRUCTOR;
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) obj_p);
|
||||
|
||||
if (!CBC_FUNCTION_IS_CONSTRUCTABLE (byte_code_p->status_flags))
|
||||
{
|
||||
#if ENABLED (JERRY_ERROR_MESSAGES)
|
||||
switch (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags))
|
||||
{
|
||||
case CBC_FUNCTION_GENERATOR:
|
||||
{
|
||||
return "Generator functions cannot be invoked with 'new'.";
|
||||
}
|
||||
case CBC_FUNCTION_ASYNC:
|
||||
{
|
||||
return "Async functions cannot be invoked with 'new'.";
|
||||
}
|
||||
case CBC_FUNCTION_ASYNC_GENERATOR:
|
||||
{
|
||||
return "Async generator functions cannot be invoked with 'new'.";
|
||||
}
|
||||
case CBC_FUNCTION_ACCESSOR:
|
||||
{
|
||||
return "Accessor functions cannot be invoked with 'new'.";
|
||||
}
|
||||
case CBC_FUNCTION_METHOD:
|
||||
{
|
||||
return "Methods cannot be invoked with 'new'.";
|
||||
}
|
||||
case CBC_FUNCTION_ARROW:
|
||||
{
|
||||
return "Arrow functions cannot be invoked with 'new'.";
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ASYNC_ARROW);
|
||||
return "Async arrow functions cannot be invoked with 'new'.";
|
||||
}
|
||||
}
|
||||
#else /* !ENABLED (JERRY_ERROR_MESSAGES) */
|
||||
return NULL;
|
||||
#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_NEXT) */
|
||||
|
||||
return ECMA_IS_VALID_CONSTRUCTOR;
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_PROXY)
|
||||
if (ECMA_OBJECT_TYPE_IS_PROXY (type))
|
||||
{
|
||||
return ECMA_GET_SECOND_BIT_FROM_POINTER_TAG (obj_p->u1.property_list_cp) != 0;
|
||||
if (ECMA_GET_SECOND_BIT_FROM_POINTER_TAG (obj_p->u1.property_list_cp) == 0)
|
||||
{
|
||||
return ECMA_ERR_MSG ("Proxy target is not a constructor.");
|
||||
}
|
||||
|
||||
return ECMA_IS_VALID_CONSTRUCTOR;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
|
||||
|
||||
if (type == ECMA_OBJECT_TYPE_FUNCTION)
|
||||
JERRY_ASSERT (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
|
||||
if (ecma_get_object_is_builtin (obj_p))
|
||||
{
|
||||
return (!ecma_get_object_is_builtin (obj_p) || !ecma_builtin_function_is_routine (obj_p));
|
||||
return ECMA_ERR_MSG ("Built-ins are not constructors.");
|
||||
}
|
||||
|
||||
JERRY_ASSERT (type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
|
||||
return !ecma_get_object_is_builtin (obj_p);
|
||||
return ECMA_IS_VALID_CONSTRUCTOR;
|
||||
} /* ecma_object_check_constructor */
|
||||
|
||||
/**
|
||||
* Implement IsConstructor abstract operation.
|
||||
*
|
||||
* @return ECMA_IS_VALID_CONSTRUCTOR - if the input value is a constructor.
|
||||
* any other value - if the input value is not a valid constructor, the pointer contains the error message.
|
||||
*/
|
||||
inline char *JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_check_constructor (ecma_value_t value) /**< ecma object */
|
||||
{
|
||||
if (!ecma_is_value_object (value))
|
||||
{
|
||||
return ECMA_ERR_MSG ("Invalid type for constructor call.");
|
||||
}
|
||||
|
||||
return ecma_object_check_constructor (ecma_get_object_from_value (value));
|
||||
} /* ecma_check_constructor */
|
||||
|
||||
/**
|
||||
* Checks whether the given object implements [[Construct]].
|
||||
*
|
||||
* @return true - if the given object is constructor;
|
||||
* false - otherwise
|
||||
*/
|
||||
inline bool JERRY_ATTR_ALWAYS_INLINE
|
||||
ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */
|
||||
{
|
||||
return ecma_object_check_constructor (obj_p) == ECMA_IS_VALID_CONSTRUCTOR;
|
||||
} /* ecma_object_is_constructor */
|
||||
|
||||
/**
|
||||
@ -634,30 +730,6 @@ ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< fun
|
||||
#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
|
||||
} /* ecma_op_function_get_compiled_code */
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
/**
|
||||
* Check whether the given object [[FunctionKind]] internal slot value is "generator".
|
||||
*
|
||||
* @return true - if the given object is a generator function
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
ecma_op_function_is_generator (ecma_object_t *obj_p) /**< object */
|
||||
{
|
||||
if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION
|
||||
&& !ecma_get_object_is_builtin (obj_p))
|
||||
{
|
||||
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) obj_p;
|
||||
const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_obj_p);
|
||||
|
||||
return CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_GENERATOR;
|
||||
}
|
||||
|
||||
return false;
|
||||
} /* ecma_op_function_is_generator */
|
||||
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
/**
|
||||
* 15.3.5.3 implementation of [[HasInstance]] for Function objects
|
||||
*
|
||||
@ -821,7 +893,9 @@ ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p) /**< function
|
||||
/**
|
||||
* Ordinary internal method: GetPrototypeFromConstructor (constructor, intrinsicDefaultProto)
|
||||
*
|
||||
* See also: ECMAScript v6, 9.1.15
|
||||
* See also:
|
||||
* - ECMAScript v6, 9.1.15
|
||||
* - ECMAScript v10, 9.1.14
|
||||
*
|
||||
* @return NULL - if the operation fail (exception on the global context is raised)
|
||||
* pointer to the prototype object - otherwise
|
||||
@ -830,7 +904,7 @@ ecma_object_t *
|
||||
ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< constructor to get prototype from */
|
||||
ecma_builtin_id_t default_proto_id) /**< intrinsicDefaultProto */
|
||||
{
|
||||
JERRY_ASSERT (ecma_object_is_constructor (ctor_obj_p));
|
||||
JERRY_ASSERT (ecma_op_object_is_callable (ctor_obj_p));
|
||||
JERRY_ASSERT (default_proto_id < ECMA_BUILTIN_ID__COUNT);
|
||||
|
||||
ecma_value_t proto = ecma_op_object_get_by_magic_id (ctor_obj_p, LIT_MAGIC_STRING_PROTOTYPE);
|
||||
@ -1322,55 +1396,6 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p;
|
||||
const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_obj_p);
|
||||
|
||||
if (!CBC_FUNCTION_IS_CONSTRUCTABLE (byte_code_p->status_flags))
|
||||
{
|
||||
const char *message_p;
|
||||
|
||||
switch (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags))
|
||||
{
|
||||
case CBC_FUNCTION_GENERATOR:
|
||||
{
|
||||
message_p = ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
case CBC_FUNCTION_ASYNC:
|
||||
{
|
||||
message_p = ECMA_ERR_MSG ("Async functions cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
case CBC_FUNCTION_ASYNC_GENERATOR:
|
||||
{
|
||||
message_p = ECMA_ERR_MSG ("Async generator functions cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
case CBC_FUNCTION_ARROW:
|
||||
{
|
||||
message_p = ECMA_ERR_MSG ("Arrow functions cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
case CBC_FUNCTION_ASYNC_ARROW:
|
||||
{
|
||||
message_p = ECMA_ERR_MSG ("Async arrow functions cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
case CBC_FUNCTION_METHOD:
|
||||
{
|
||||
message_p = ECMA_ERR_MSG ("Methods cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ACCESSOR);
|
||||
|
||||
message_p = ECMA_ERR_MSG ("Accessor functions cannot be invoked with 'new'.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ecma_raise_type_error (message_p);
|
||||
}
|
||||
|
||||
/* 5. */
|
||||
if (!ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_obj_p->u.function.scope_cp))
|
||||
|
||||
@ -37,6 +37,16 @@ bool ecma_op_object_is_callable (ecma_object_t *obj_p);
|
||||
bool ecma_is_constructor (ecma_value_t value);
|
||||
bool ecma_object_is_constructor (ecma_object_t *obj_p);
|
||||
|
||||
/**
|
||||
* Special constant indicating that the value is a valid constructor
|
||||
*
|
||||
* Use after the ecma_*_check_constructor calls.
|
||||
*/
|
||||
#define ECMA_IS_VALID_CONSTRUCTOR ((char *) 0x1)
|
||||
|
||||
char *ecma_object_check_constructor (ecma_object_t *obj_p);
|
||||
char *ecma_check_constructor (ecma_value_t value);
|
||||
|
||||
ecma_object_t *
|
||||
ecma_op_create_simple_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p);
|
||||
|
||||
@ -72,9 +82,6 @@ void
|
||||
ecma_op_native_handler_list_lazy_property_names (ecma_object_t *object_p,
|
||||
ecma_collection_t *prop_names_p,
|
||||
ecma_property_counter_t *prop_counter_p);
|
||||
|
||||
bool
|
||||
ecma_op_function_is_generator (ecma_object_t *func_obj_p);
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
ecma_object_t *
|
||||
|
||||
@ -1314,8 +1314,7 @@ opfunc_init_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
|
||||
else if (!ecma_is_value_null (super_class))
|
||||
{
|
||||
/* 6.f, 6.g.i */
|
||||
if (!ecma_is_constructor (super_class)
|
||||
|| ecma_op_function_is_generator (ecma_get_object_from_value (super_class)))
|
||||
if (!ecma_is_constructor (super_class))
|
||||
{
|
||||
return ecma_raise_type_error ("Class extends value is not a constructor or null");
|
||||
}
|
||||
|
||||
@ -691,10 +691,10 @@ vm_spread_operation (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
|
||||
if (frame_ctx_p->byte_code_p[1] == CBC_EXT_SPREAD_NEW)
|
||||
{
|
||||
if (!ecma_is_value_object (func_value)
|
||||
|| !ecma_object_is_constructor (ecma_get_object_from_value (func_value)))
|
||||
const char *constructor_message_p = ecma_check_constructor (func_value);
|
||||
if (constructor_message_p != ECMA_IS_VALID_CONSTRUCTOR)
|
||||
{
|
||||
completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor."));
|
||||
completion_value = ecma_raise_type_error (constructor_message_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -879,10 +879,10 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
ecma_value_t constructor_value = stack_top_p[-1];
|
||||
ecma_value_t completion_value;
|
||||
|
||||
if (!ecma_is_value_object (constructor_value)
|
||||
|| !ecma_object_is_constructor (ecma_get_object_from_value (constructor_value)))
|
||||
const char *constructor_message_p = ecma_check_constructor (constructor_value);
|
||||
if (constructor_message_p != ECMA_IS_VALID_CONSTRUCTOR)
|
||||
{
|
||||
completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor."));
|
||||
completion_value = ecma_raise_type_error (constructor_message_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -318,7 +318,6 @@
|
||||
<test id="built-ins/TypedArrayConstructors/ctors-bigint/object-arg/custom-proto-access-throws.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors-bigint/object-arg/use-custom-proto-if-object.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/custom-proto-access-throws.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/buffer-arg/byteoffset-is-negative-zero.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/buffer-arg/custom-proto-access-throws.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/buffer-arg/defined-negative-length.js"><reason></reason></test>
|
||||
@ -333,7 +332,6 @@
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/object-arg/returns.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/object-arg/use-custom-proto-if-object.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/typedarray-arg/custom-proto-access-throws.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/ctors/typedarray-arg/use-custom-proto-if-object.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/from/BigInt/custom-ctor-returns-other-instance.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/from/BigInt/custom-ctor.js"><reason></reason></test>
|
||||
@ -368,7 +366,6 @@
|
||||
<test id="built-ins/TypedArrayConstructors/of/custom-ctor-returns-other-instance.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/of/custom-ctor.js"><reason></reason></test>
|
||||
<test id="built-ins/TypedArrayConstructors/of/new-instance-using-custom-ctor.js"><reason></reason></test>
|
||||
<test id="harness/isConstructor.js"><reason></reason></test>
|
||||
<test id="language/block-scope/syntax/redeclaration/async-function-name-redeclaration-attempt-with-async-function.js"><reason></reason></test>
|
||||
<test id="language/block-scope/syntax/redeclaration/async-function-name-redeclaration-attempt-with-function.js"><reason></reason></test>
|
||||
<test id="language/block-scope/syntax/redeclaration/async-function-name-redeclaration-attempt-with-generator.js"><reason></reason></test>
|
||||
@ -730,9 +727,7 @@
|
||||
<test id="language/statements/class/dstr/meth-static-ary-init-iter-no-close.js"><reason></reason></test>
|
||||
<test id="language/statements/class/dstr/meth-static-dflt-ary-init-iter-no-close.js"><reason></reason></test>
|
||||
<test id="language/statements/class/subclass/default-constructor-spread-override.js"><reason></reason></test>
|
||||
<test id="language/statements/class/subclass/superclass-arrow-function.js"><reason></reason></test>
|
||||
<test id="language/statements/class/subclass/superclass-async-function.js"><reason></reason></test>
|
||||
<test id="language/statements/class/subclass/superclass-generator-function.js"><reason></reason></test>
|
||||
<test id="language/statements/class/super/in-constructor-superproperty-evaluation.js"><reason></reason></test>
|
||||
<test id="language/statements/const/dstr/ary-init-iter-no-close.js"><reason></reason></test>
|
||||
<test id="language/statements/do-while/cptn-abrupt-empty.js"><reason></reason></test>
|
||||
@ -9176,7 +9171,6 @@
|
||||
<test id="language/statements/class/elements/same-line-async-gen-static-private-methods-with-fields.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/same-line-async-gen-static-private-methods.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/syntax/valid/grammar-static-private-async-gen-meth-prototype.js"><reason></reason></test>
|
||||
<test id="language/statements/class/subclass/superclass-async-generator-function.js"><reason></reason></test>
|
||||
<test id="language/statements/for-await-of/async-from-sync-iterator-continuation-abrupt-completion-get-constructor.js"><reason></reason></test>
|
||||
<test id="language/statements/for-await-of/async-func-decl-dstr-array-elem-init-simple-no-strict.js"><reason></reason></test>
|
||||
<test id="language/statements/for-await-of/async-func-decl-dstr-array-elem-init-yield-ident-invalid.js"><reason></reason></test>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user