Skip to content

Commit 99ea9f4

Browse files
author
Irina Yatsenko
committed
[MERGE #5566 @irinayat-MS] Throw if cannot delete indexed array's property in strict mode
Merge pull request #5566 from irinayat-MS:DeleteFromFrozenArray Fixes #5564 Another case (array object is either sealed or frozen) when we weren't throwing in strict mode on delete of effectively non-configurable property.
2 parents d28a85a + 93b1af6 commit 99ea9f4

File tree

2 files changed

+59
-19
lines changed

2 files changed

+59
-19
lines changed

lib/Runtime/Types/ES5ArrayTypeHandler.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,14 @@ namespace Js
656656
// Not in attribute map
657657
if (!(GetDataItemAttributes() & PropertyConfigurable))
658658
{
659-
return !HasDataItem(arr, index); // CantDelete
659+
if (HasDataItem(arr, index))
660+
{
661+
JavascriptError::ThrowCantDeleteIfStrictModeOrNonconfigurable(
662+
propertyOperationFlags, instance->GetScriptContext(), TaggedInt::ToString(index, instance->GetScriptContext())->GetString());
663+
664+
return false;
665+
}
666+
return true; // non-existing non-configurable property can be deleted
660667
}
661668
return arr->DirectDeleteItemAt<Var>(index);
662669
}

test/Array/delete.js

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@ var tests = [
1919
assert.areEqual('whatever', arr.non_indexed, "arr.non_indexed is set to 'whatever'");
2020
assert.areEqual('with getter', arr.with_getter, "arr.with_getter is set to 'with getter'");
2121

22-
var res = delete arr.non_indexed;
23-
assert.areEqual(true, res, "Deleting own property should succeed");
22+
assert.areEqual(true, delete arr.non_indexed, "Deleting own property should succeed");
2423
assert.areEqual(undefined, arr.non_indexed, "arr.non_indexed has been deleted");
2524

26-
var res = delete arr.with_getter;
27-
assert.areEqual(true, res, "Deleting own property with a getter should succeed");
25+
assert.areEqual(true, delete arr.with_getter, "Deleting own property with a getter should succeed");
2826
assert.areEqual(undefined, arr.with_getter, "arr.with_getter has been deleted");
2927
}
3028
},
@@ -35,8 +33,7 @@ var tests = [
3533
var id = 'id';
3634
Object.defineProperty(arr, id, { value: 17, configurable: false });
3735

38-
var res = delete arr[id];
39-
assert.areEqual(false, res);
36+
assert.areEqual(false, delete arr[id]);
4037
assert.areEqual(17, arr[id], "arr['id'] value after failed delete");
4138

4239
assert.throws(function () { 'use strict'; delete arr[id]; }, TypeError,
@@ -49,8 +46,7 @@ var tests = [
4946
body: function () {
5047
var arr = [1,4,9,16];
5148

52-
var res = delete arr.length;
53-
assert.areEqual(false, res, "delete of arr.length should fail (as noop)");
49+
assert.areEqual(false, delete arr.length, "delete of arr.length should fail (as noop)");
5450
assert.areEqual(4, arr.length, "arr.length after attempting to delete it");
5551

5652
assert.throws(function () { 'use strict'; delete arr.length; }, TypeError,
@@ -64,18 +60,15 @@ var tests = [
6460
body: function () {
6561
var arr = [1,4,9,16];
6662

67-
var res = delete arr[1];
68-
assert.areEqual(true, res, "delete of arr[1] should succeed");
63+
assert.areEqual(true, delete arr[1], "delete of arr[1] should succeed");
6964
assert.areEqual(undefined, arr[1], "arr[1] value after delete should be undefined");
7065
assert.areEqual(4, arr.length, "the array's lenght should not change");
7166

72-
res = delete arr[42];
73-
assert.areEqual(true, res, "delete of arr[42] (beyond the array bounds) should succeed");
67+
assert.areEqual(true, delete arr[42], "delete of arr[42] (beyond the array bounds) should succeed");
7468
assert.areEqual(4, arr.length, "the array's length is unchanged");
7569

7670
const last = arr.length - 1;
77-
res = delete arr[last];
78-
assert.areEqual(true, res, "delete of last element should succeed");
71+
assert.areEqual(true, delete arr[last], "delete of last element should succeed");
7972
assert.areEqual(undefined, arr[last], "arr[last] value after delete should be undefined");
8073
assert.areEqual(4, arr.length, "the array's lenght should not change");
8174
}
@@ -87,16 +80,56 @@ var tests = [
8780
Array.prototype[1] = "arr.proto";
8881
var arr = [1,4,9,16,25];
8982

90-
var res = delete arr[1];
91-
assert.areEqual(true, res, "delete of arr[1] should succeed");
83+
assert.areEqual(true, delete arr[1], "delete of arr[1] should succeed");
9284
assert.areEqual("arr.proto", arr[1], "arr[1] after deleting should be picked up from the Array prototype");
9385

94-
var res = delete arr[4];
95-
assert.areEqual(true, res, "delete of arr[4] should succeed");
86+
assert.areEqual(true, delete arr[4], "delete of arr[4] should succeed");
9687
assert.areEqual("obj.proto", arr[4], "arr[4] after deleting should be picked up from the Object prototype");
9788
assert.areEqual(5, arr.length, "arr.length after deleting of the last element");
9889
}
9990
},
91+
{
92+
name: "Deleting of properties on frozen Arrays",
93+
body: function () {
94+
var arr = [42];
95+
arr.foo = 'fourty-two';
96+
97+
Object.freeze(arr);
98+
99+
// indexed property
100+
assert.areEqual(false, delete arr[0], "delete arr[0] from frozen array");
101+
assert.throws(function () { 'use strict'; delete arr[0]; }, TypeError,
102+
"Should throw on delete of non-indexed property in array",
103+
"Calling delete on '0' is not allowed in strict mode");
104+
105+
// non-indexed property
106+
assert.areEqual(false, delete arr.foo, "delete arr.foo from frozen array");
107+
assert.throws(function () { 'use strict'; delete arr.foo; }, TypeError,
108+
"Should throw on delete of non-indexed property in array",
109+
"Calling delete on 'foo' is not allowed in strict mode");
110+
}
111+
},
112+
{
113+
name: "Deleting of indexed properties on sealed Arrays",
114+
body: function () {
115+
var arr = [42];
116+
arr.foo = 'fourty-two';
117+
118+
Object.seal(arr);
119+
120+
// indexed property
121+
assert.areEqual(false, delete arr[0], "delete arr[0] from sealed array");
122+
assert.throws(function () { 'use strict'; delete arr[0]; }, TypeError,
123+
"Should throw on delete of non-indexed property in array",
124+
"Calling delete on '0' is not allowed in strict mode");
125+
126+
// non-indexed property
127+
assert.areEqual(false, delete arr.foo, "delete arr.foo from sealed array");
128+
assert.throws(function () { 'use strict'; delete arr.foo; }, TypeError,
129+
"Should throw on delete of non-indexed property in array",
130+
"Calling delete on 'foo' is not allowed in strict mode");
131+
}
132+
},
100133
];
101134

102135
testRunner.runTests(tests, { verbose: false /*so no need to provide baseline*/ });

0 commit comments

Comments
 (0)