Ensure that fast arrays length property is always writable (#4559)

Also remove legacy `ecma_array_object_set_length_flags_t`.

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
Robert Fancsik 2021-02-03 19:12:15 +01:00 committed by GitHub
parent 1712ad5dc4
commit c82f184f00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 48 deletions

View File

@ -972,7 +972,7 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
ecma_value_t new_value, /**< new length value */
uint32_t flags) /**< configuration options */
{
bool is_throw = (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW);
bool is_throw = (flags & ECMA_PROP_IS_THROW) != 0;
ecma_number_t new_len_num;
ecma_value_t completion = ecma_op_to_number (new_value, &new_len_num);
@ -1000,7 +1000,11 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid Array length"));
}
if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT)
/* Only the writable and data properties can be modified. */
if (flags & (ECMA_PROP_IS_CONFIGURABLE
| ECMA_PROP_IS_ENUMERABLE
| ECMA_PROP_IS_GET_DEFINED
| ECMA_PROP_IS_SET_DEFINED))
{
return ecma_reject (is_throw);
}
@ -1012,10 +1016,15 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
if (new_len_num == old_len_uint32)
{
/* Only the writable flag must be updated. */
if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED)
if (flags & ECMA_PROP_IS_WRITABLE_DEFINED)
{
if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE))
if (!(flags & ECMA_PROP_IS_WRITABLE))
{
if (ecma_op_array_is_fast_array (ext_object_p))
{
ecma_fast_array_convert_to_normal (object_p);
}
ext_object_p->u.array.length_prop_and_hole_count &= (uint32_t) ~ECMA_PROPERTY_FLAG_WRITABLE;
}
else if (!ecma_is_property_writable ((ecma_property_t) ext_object_p->u.array.length_prop_and_hole_count))
@ -1043,9 +1052,14 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
ext_object_p->u.array.length = current_len_uint32;
if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED)
&& !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE))
if ((flags & ECMA_PROP_IS_WRITABLE_DEFINED)
&& !(flags & ECMA_PROP_IS_WRITABLE))
{
if (ecma_op_array_is_fast_array (ext_object_p))
{
ecma_fast_array_convert_to_normal (object_p);
}
ext_object_p->u.array.length_prop_and_hole_count &= (uint32_t) ~ECMA_PROPERTY_FLAG_WRITABLE;
}
@ -1093,41 +1107,15 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra
JERRY_ASSERT ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
|| !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE));
uint32_t flags = 0;
if (property_desc_p->flags & ECMA_PROP_IS_THROW)
{
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW;
}
/* Only the writable and data properties can be modified. */
if (property_desc_p->flags & (ECMA_PROP_IS_CONFIGURABLE
| ECMA_PROP_IS_ENUMERABLE
| ECMA_PROP_IS_GET_DEFINED
| ECMA_PROP_IS_SET_DEFINED))
{
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT;
}
if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
{
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED;
}
if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE)
{
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE;
}
if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
{
return ecma_op_array_object_set_length (object_p, property_desc_p->value, flags);
return ecma_op_array_object_set_length (object_p, property_desc_p->value, property_desc_p->flags);
}
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
ecma_value_t length_value = ecma_make_uint32_value (ext_object_p->u.array.length);
ecma_value_t result = ecma_op_array_object_set_length (object_p, length_value, flags);
ecma_value_t result = ecma_op_array_object_set_length (object_p, length_value, property_desc_p->flags);
ecma_fast_free_value (length_value);
return result;

View File

@ -25,6 +25,21 @@
* @{
*/
/**
* Attributes of fast access mode arrays:
*
* - The internal property is replaced with a buffer which directly stores the values
* - Whenever any operation would change the following attributes of the array it should be converted back to normal
* - All properties must be enumerable configurable writable data properties
* - The prototype must be Array.prototype
* - [[Extensible]] internal property must be true
* - 'length' property of the array must be writable
*
* - The conversion is also required when a property is set if:
* - The property name is not an array index
* - The new hole count of the array would reach ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT
*/
/**
* Maximum number of new array holes in a fast mode access array.
* If the number of new holes exceeds this limit, the array is converted back
@ -47,20 +62,6 @@
*/
#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT (1 << 24)
/**
* Flags for ecma_op_array_object_set_length
*/
typedef enum
{
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW = 1u << 0, /**< is_throw flag is set */
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT = 1u << 1, /**< reject later because the descriptor flags
* contains an unallowed combination */
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED = 1u << 2, /**< writable flag defined
* in the property descriptor */
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE = 1u << 3, /**< writable flag enabled
* in the property descriptor */
} ecma_array_object_set_length_flags_t;
ecma_object_t *
ecma_op_new_array_object (uint32_t length);

View File

@ -155,3 +155,16 @@ for (i = 0; i < 1024; i++)
var elision = [0,,2 ,3];
assert (elision.hasOwnProperty(1) == false);
(function () {
"use strict";
var arr = [1];
Object.defineProperty (arr, "length", {value: 1, writable: false});
try {
arr[2] = 5;
assert (false);
} catch (e) {
assert (e instanceof TypeError);
}
}) ();