Skip to content

Commit c82f184

Browse files
authored
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 [email protected]
1 parent 1712ad5 commit c82f184

File tree

3 files changed

+50
-48
lines changed

3 files changed

+50
-48
lines changed

jerry-core/ecma/operations/ecma-array-object.c

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
972972
ecma_value_t new_value, /**< new length value */
973973
uint32_t flags) /**< configuration options */
974974
{
975-
bool is_throw = (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW);
975+
bool is_throw = (flags & ECMA_PROP_IS_THROW) != 0;
976976
ecma_number_t new_len_num;
977977
ecma_value_t completion = ecma_op_to_number (new_value, &new_len_num);
978978

@@ -1000,7 +1000,11 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
10001000
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid Array length"));
10011001
}
10021002

1003-
if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT)
1003+
/* Only the writable and data properties can be modified. */
1004+
if (flags & (ECMA_PROP_IS_CONFIGURABLE
1005+
| ECMA_PROP_IS_ENUMERABLE
1006+
| ECMA_PROP_IS_GET_DEFINED
1007+
| ECMA_PROP_IS_SET_DEFINED))
10041008
{
10051009
return ecma_reject (is_throw);
10061010
}
@@ -1012,10 +1016,15 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object
10121016
if (new_len_num == old_len_uint32)
10131017
{
10141018
/* Only the writable flag must be updated. */
1015-
if (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED)
1019+
if (flags & ECMA_PROP_IS_WRITABLE_DEFINED)
10161020
{
1017-
if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE))
1021+
if (!(flags & ECMA_PROP_IS_WRITABLE))
10181022
{
1023+
if (ecma_op_array_is_fast_array (ext_object_p))
1024+
{
1025+
ecma_fast_array_convert_to_normal (object_p);
1026+
}
1027+
10191028
ext_object_p->u.array.length_prop_and_hole_count &= (uint32_t) ~ECMA_PROPERTY_FLAG_WRITABLE;
10201029
}
10211030
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
10431052

10441053
ext_object_p->u.array.length = current_len_uint32;
10451054

1046-
if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED)
1047-
&& !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE))
1055+
if ((flags & ECMA_PROP_IS_WRITABLE_DEFINED)
1056+
&& !(flags & ECMA_PROP_IS_WRITABLE))
10481057
{
1058+
if (ecma_op_array_is_fast_array (ext_object_p))
1059+
{
1060+
ecma_fast_array_convert_to_normal (object_p);
1061+
}
1062+
10491063
ext_object_p->u.array.length_prop_and_hole_count &= (uint32_t) ~ECMA_PROPERTY_FLAG_WRITABLE;
10501064
}
10511065

@@ -1093,41 +1107,15 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra
10931107
JERRY_ASSERT ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
10941108
|| !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE));
10951109

1096-
uint32_t flags = 0;
1097-
1098-
if (property_desc_p->flags & ECMA_PROP_IS_THROW)
1099-
{
1100-
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW;
1101-
}
1102-
1103-
/* Only the writable and data properties can be modified. */
1104-
if (property_desc_p->flags & (ECMA_PROP_IS_CONFIGURABLE
1105-
| ECMA_PROP_IS_ENUMERABLE
1106-
| ECMA_PROP_IS_GET_DEFINED
1107-
| ECMA_PROP_IS_SET_DEFINED))
1108-
{
1109-
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT;
1110-
}
1111-
1112-
if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
1113-
{
1114-
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED;
1115-
}
1116-
1117-
if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE)
1118-
{
1119-
flags |= ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE;
1120-
}
1121-
11221110
if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
11231111
{
1124-
return ecma_op_array_object_set_length (object_p, property_desc_p->value, flags);
1112+
return ecma_op_array_object_set_length (object_p, property_desc_p->value, property_desc_p->flags);
11251113
}
11261114

11271115
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
11281116
ecma_value_t length_value = ecma_make_uint32_value (ext_object_p->u.array.length);
11291117

1130-
ecma_value_t result = ecma_op_array_object_set_length (object_p, length_value, flags);
1118+
ecma_value_t result = ecma_op_array_object_set_length (object_p, length_value, property_desc_p->flags);
11311119

11321120
ecma_fast_free_value (length_value);
11331121
return result;

jerry-core/ecma/operations/ecma-array-object.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@
2525
* @{
2626
*/
2727

28+
/**
29+
* Attributes of fast access mode arrays:
30+
*
31+
* - The internal property is replaced with a buffer which directly stores the values
32+
* - Whenever any operation would change the following attributes of the array it should be converted back to normal
33+
* - All properties must be enumerable configurable writable data properties
34+
* - The prototype must be Array.prototype
35+
* - [[Extensible]] internal property must be true
36+
* - 'length' property of the array must be writable
37+
*
38+
* - The conversion is also required when a property is set if:
39+
* - The property name is not an array index
40+
* - The new hole count of the array would reach ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT
41+
*/
42+
2843
/**
2944
* Maximum number of new array holes in a fast mode access array.
3045
* If the number of new holes exceeds this limit, the array is converted back
@@ -47,20 +62,6 @@
4762
*/
4863
#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT (1 << 24)
4964

50-
/**
51-
* Flags for ecma_op_array_object_set_length
52-
*/
53-
typedef enum
54-
{
55-
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW = 1u << 0, /**< is_throw flag is set */
56-
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_REJECT = 1u << 1, /**< reject later because the descriptor flags
57-
* contains an unallowed combination */
58-
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED = 1u << 2, /**< writable flag defined
59-
* in the property descriptor */
60-
ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE = 1u << 3, /**< writable flag enabled
61-
* in the property descriptor */
62-
} ecma_array_object_set_length_flags_t;
63-
6465
ecma_object_t *
6566
ecma_op_new_array_object (uint32_t length);
6667

tests/jerry/array.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,16 @@ for (i = 0; i < 1024; i++)
155155

156156
var elision = [0,,2 ,3];
157157
assert (elision.hasOwnProperty(1) == false);
158+
159+
(function () {
160+
"use strict";
161+
var arr = [1];
162+
Object.defineProperty (arr, "length", {value: 1, writable: false});
163+
164+
try {
165+
arr[2] = 5;
166+
assert (false);
167+
} catch (e) {
168+
assert (e instanceof TypeError);
169+
}
170+
}) ();

0 commit comments

Comments
 (0)