Skip to content

Commit 2d3e735

Browse files
ofrobotsMylesBorins
authored andcommitted
deps: V8: backport e560815 from upstream
Original commit message: [runtime] Fix Array.prototype.concat with complex @@species Array.prototype.concat does not properly handle JSProxy species that will modify the currently visited array. BUG=682194 Review-Url: https://codereview.chromium.org/2655623004 Cr-Commit-Position: refs/heads/master@{#42640} Refs: #12779 PR-URL: #16133 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 9ec87dc commit 2d3e735

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

deps/v8/src/builtins.cc

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -795,14 +795,18 @@ namespace {
795795
*/
796796
class ArrayConcatVisitor {
797797
public:
798-
ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage,
798+
ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> storage,
799799
bool fast_elements)
800800
: isolate_(isolate),
801801
storage_(isolate->global_handles()->Create(*storage)),
802802
index_offset_(0u),
803-
bit_field_(FastElementsField::encode(fast_elements) |
804-
ExceedsLimitField::encode(false) |
805-
IsFixedArrayField::encode(storage->IsFixedArray())) {
803+
bit_field_(
804+
FastElementsField::encode(fast_elements) |
805+
ExceedsLimitField::encode(false) |
806+
IsFixedArrayField::encode(storage->IsFixedArray()) |
807+
HasSimpleElementsField::encode(storage->IsFixedArray() ||
808+
storage->map()->instance_type() >
809+
LAST_CUSTOM_ELEMENTS_RECEIVER)) {
806810
DCHECK(!(this->fast_elements() && !is_fixed_array()));
807811
}
808812

@@ -891,12 +895,16 @@ class ArrayConcatVisitor {
891895
// (otherwise)
892896
Handle<FixedArray> storage_fixed_array() {
893897
DCHECK(is_fixed_array());
898+
DCHECK(has_simple_elements());
894899
return Handle<FixedArray>::cast(storage_);
895900
}
896901
Handle<JSReceiver> storage_jsreceiver() {
897902
DCHECK(!is_fixed_array());
898903
return Handle<JSReceiver>::cast(storage_);
899904
}
905+
bool has_simple_elements() const {
906+
return HasSimpleElementsField::decode(bit_field_);
907+
}
900908

901909
private:
902910
// Convert storage to dictionary mode.
@@ -929,12 +937,14 @@ class ArrayConcatVisitor {
929937

930938
inline void set_storage(FixedArray* storage) {
931939
DCHECK(is_fixed_array());
940+
DCHECK(has_simple_elements());
932941
storage_ = isolate_->global_handles()->Create(storage);
933942
}
934943

935944
class FastElementsField : public BitField<bool, 0, 1> {};
936945
class ExceedsLimitField : public BitField<bool, 1, 1> {};
937946
class IsFixedArrayField : public BitField<bool, 2, 1> {};
947+
class HasSimpleElementsField : public BitField<bool, 3, 1> {};
938948

939949
bool fast_elements() const { return FastElementsField::decode(bit_field_); }
940950
void set_fast_elements(bool fast) {
@@ -1166,8 +1176,6 @@ bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
11661176
visitor->increase_index_offset(length);
11671177
return true;
11681178
}
1169-
1170-
11711179
/**
11721180
* A helper function that visits "array" elements of a JSReceiver in numerical
11731181
* order.
@@ -1201,7 +1209,8 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
12011209
return IterateElementsSlow(isolate, receiver, length, visitor);
12021210
}
12031211

1204-
if (!HasOnlySimpleElements(isolate, *receiver)) {
1212+
if (!HasOnlySimpleElements(isolate, *receiver) ||
1213+
!visitor->has_simple_elements()) {
12051214
return IterateElementsSlow(isolate, receiver, length, visitor);
12061215
}
12071216
Handle<JSObject> array = Handle<JSObject>::cast(receiver);
@@ -1476,7 +1485,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
14761485
// In case of failure, fall through.
14771486
}
14781487

1479-
Handle<Object> storage;
1488+
Handle<HeapObject> storage;
14801489
if (fast_case) {
14811490
// The backing storage array must have non-existing elements to preserve
14821491
// holes across concat operations.
@@ -1494,7 +1503,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
14941503
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
14951504
isolate, storage_object,
14961505
Execution::New(isolate, species, species, 1, &length));
1497-
storage = storage_object;
1506+
storage = Handle<HeapObject>::cast(storage_object);
14981507
}
14991508

15001509
ArrayConcatVisitor visitor(isolate, storage, fast_case);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --expose-gc
6+
7+
var proxy = new Proxy([], {
8+
defineProperty() {
9+
w.length = 1; // shorten the array so the backstore pointer is relocated
10+
gc(); // force gc to move the array's elements backstore
11+
return Object.defineProperty.apply(this, arguments);
12+
}
13+
});
14+
15+
class MyArray extends Array {
16+
// custom constructor which returns a proxy object
17+
static get[Symbol.species](){
18+
return function() {
19+
return proxy;
20+
}
21+
};
22+
}
23+
24+
var w = new MyArray(100);
25+
w[1] = 0.1;
26+
w[2] = 0.1;
27+
28+
var result = Array.prototype.concat.call(w);
29+
30+
assertEquals(undefined, result[0]);
31+
assertEquals(0.1, result[1]);
32+
33+
for (var i = 2; i < 200; i++) {
34+
assertEquals(undefined, result[i]);
35+
}

0 commit comments

Comments
 (0)