[typedarray] Fix IterableToList when Number has an iterator
IterableToListCanBeElided checked that the input was always a HeapObject but this is not true when an iterator symbol is defined on the Number prototype, meaning Smi and HeapNumber can also be passed in. Added a regression test for the crash and some correctness tests for smi and double input to TA.from. Also factored out the tests in typedarray-from.js that modify global state e.g. protector cells, so that one iteration of the top level loop does not interfere with the next. Bug: chromium:814643 Change-Id: I364d11f011faf8370446f905a35a945d47e4477f Reviewed-on: https://chromium-review.googlesource.com/930962 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Peter Marshall <petermarshall@chromium.org> Cr-Commit-Position: refs/heads/master@{#51461}
This commit is contained in:
parent
ef93026137
commit
aaa78c330e
@ -1247,9 +1247,13 @@ RUNTIME_FUNCTION(Runtime_CreateDataProperty) {
|
||||
RUNTIME_FUNCTION(Runtime_IterableToListCanBeElided) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(HeapObject, obj, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
|
||||
|
||||
if (!obj->IsJSObject()) return isolate->heap()->ToBoolean(false);
|
||||
// If an iterator symbol is added to the Number prototype, we could see a Smi.
|
||||
if (obj->IsSmi()) return isolate->heap()->ToBoolean(false);
|
||||
if (!HeapObject::cast(*obj)->IsJSObject()) {
|
||||
return isolate->heap()->ToBoolean(false);
|
||||
}
|
||||
|
||||
// While iteration alone may not have observable side-effects, calling
|
||||
// toNumber on an object will. Make sure the arg is not an array of objects.
|
||||
|
@ -151,14 +151,6 @@ for (var constructor of typedArrayConstructors) {
|
||||
assertThrows(function() { constructor.from([], 'noncallable'); },
|
||||
TypeError);
|
||||
|
||||
source = [1, 2, 3];
|
||||
source[Symbol.iterator] = undefined;
|
||||
assertArrayLikeEquals(constructor.from(source), source, constructor);
|
||||
|
||||
source = [{ valueOf: function(){ return 42; }}];
|
||||
source[Symbol.iterator] = undefined;
|
||||
assertArrayLikeEquals(constructor.from(source), [42], constructor);
|
||||
|
||||
source = [1, 2, 3];
|
||||
var proxy = new Proxy(source, {});
|
||||
assertArrayLikeEquals(constructor.from(proxy), source, constructor);
|
||||
@ -171,6 +163,26 @@ for (var constructor of typedArrayConstructors) {
|
||||
}
|
||||
});
|
||||
assertArrayLikeEquals(constructor.from(proxy), [2, 3, 4], constructor);
|
||||
}
|
||||
|
||||
// Tests that modify global state in a way that affects fast paths e.g. by
|
||||
// invalidating protectors or changing prototypes.
|
||||
for (var constructor of typedArrayConstructors) {
|
||||
source = [1, 2, 3];
|
||||
source[Symbol.iterator] = undefined;
|
||||
assertArrayLikeEquals(constructor.from(source), source, constructor);
|
||||
|
||||
source = [{ valueOf: function(){ return 42; }}];
|
||||
source[Symbol.iterator] = undefined;
|
||||
assertArrayLikeEquals(constructor.from(source), [42], constructor);
|
||||
|
||||
Number.prototype[Symbol.iterator] = function* () {
|
||||
yield 1;
|
||||
yield 2;
|
||||
yield 3;
|
||||
}
|
||||
assertArrayLikeEquals(constructor.from(1), [1, 2, 3], constructor);
|
||||
assertArrayLikeEquals(constructor.from(1.1), [1, 2, 3], constructor);
|
||||
|
||||
var nullIterator = {};
|
||||
nullIterator[Symbol.iterator] = null;
|
||||
|
6
test/mjsunit/regress/regress-814643.js
Normal file
6
test/mjsunit/regress/regress-814643.js
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
Number.prototype.__proto__ = String.prototype;
|
||||
Uint8Array.from(1);
|
Loading…
Reference in New Issue
Block a user