Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (203203 => 203204)
--- trunk/Source/_javascript_Core/ChangeLog 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-07-14 00:15:03 UTC (rev 203204)
@@ -1,3 +1,44 @@
+2016-07-13 Keith Miller <[email protected]>
+
+ Crashes with detached ArrayBuffers
+ https://bugs.webkit.org/show_bug.cgi?id=157088
+ <rdar://problem/27327362>
+
+ Reviewed by Filip Pizlo.
+
+ TypedArray.prototype.fill was incorrect because it should perform
+ ToNumber coercion each time it tries to store the
+ object. Currently, we only perform the coercion once at the
+ beginning of the loop. If we find that we need to improve the
+ performance of this function, we can add a faster C++ path back
+ that only handles the primitive case.
+
+ This patch also moves the isNeutered() checks from put and
+ putByIndex into setIndex. This fixes an issue where setIndex might
+ store to a no longer valid offset.
+
+ * builtins/TypedArrayPrototype.js:
+ (globalPrivate.typedArrayClampArgumentToStartOrEnd):
+ (fill):
+ * runtime/JSGenericTypedArrayView.h:
+ (JSC::JSGenericTypedArrayView::setIndexQuickly):
+ (JSC::JSGenericTypedArrayView::setIndex):
+ (JSC::JSGenericTypedArrayView::setRangeToValue): Deleted.
+ * runtime/JSGenericTypedArrayViewInlines.h:
+ (JSC::JSGenericTypedArrayView<Adaptor>::put): Deleted.
+ (JSC::JSGenericTypedArrayView<Adaptor>::putByIndex): Deleted.
+ * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+ (JSC::genericTypedArrayViewProtoFuncFill): Deleted.
+ * runtime/JSTypedArrayViewPrototype.cpp:
+ (JSC::JSTypedArrayViewPrototype::finishCreation):
+ (JSC::typedArrayViewProtoFuncFill): Deleted.
+ * tests/stress/typedarray-fill.js:
+ * tests/stress/typedarray-functions-with-neutered.js:
+ (defaultForArg):
+ (test2):
+ (checkArgumentsForType): Deleted.
+ (checkArguments): Deleted.
+
2016-07-13 Michael Saboff <[email protected]>
Some bad unicode regex escapes aren't flagged as errors
Modified: trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js (203203 => 203204)
--- trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js 2016-07-14 00:15:03 UTC (rev 203204)
@@ -52,6 +52,22 @@
return constructor;
}
+@globalPrivate
+function typedArrayClampArgumentToStartOrEnd(value, length, undefinedValue)
+{
+ "use strict";
+
+ if (value === @undefined)
+ return undefinedValue;
+
+ let int = @toInteger(value);
+ if (int < 0) {
+ int += length;
+ return int < 0 ? 0 : int;
+ }
+ return int > length ? length : int;
+}
+
function values()
{
"use strict";
@@ -90,6 +106,29 @@
return true;
}
+function fill(value /* [, start [, end]] */)
+{
+ "use strict";
+
+ let length = @typedArrayLength(this);
+ let start;
+ let end;
+
+ if (arguments.length > 1) {
+ start = arguments[1];
+ if (arguments.length > 2) {
+ end = arguments[2];
+ }
+ }
+
+ start = @typedArrayClampArgumentToStartOrEnd(start, length, 0);
+ end = @typedArrayClampArgumentToStartOrEnd(end, length, length);
+
+ for (let i = start; i < end; i++)
+ this[i] = value;
+ return this;
+}
+
function find(callback /* [, thisArg] */)
{
"use strict";
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h (203203 => 203204)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h 2016-07-14 00:15:03 UTC (rev 203204)
@@ -88,6 +88,8 @@
Unobservable,
};
+static const char* typedArrayBufferHasBeenDetachedErrorMessage = "Underlying ArrayBuffer has been detached from the view";
+
template<typename Adaptor>
class JSGenericTypedArrayView : public JSArrayBufferView {
public:
@@ -160,6 +162,7 @@
void setIndexQuickly(unsigned i, JSValue value)
{
+ ASSERT(!value.isObject());
setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value));
}
@@ -169,6 +172,11 @@
if (exec->hadException())
return false;
+ if (isNeutered()) {
+ throwTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+ return false;
+ }
+
if (i >= m_length)
return false;
@@ -180,22 +188,6 @@
static bool toAdaptorNativeFromValue(ExecState* exec, JSValue jsValue, ElementType& result) { return toNativeFromValue<Adaptor>(exec, jsValue, result); }
- bool setRangeToValue(ExecState* exec, unsigned start, unsigned end, JSValue jsValue)
- {
- ASSERT(0 <= start && start <= end && end <= m_length);
-
- typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue);
- if (exec->hadException())
- return false;
-
- // We might want to do something faster here (e.g. SIMD) if this is too slow.
- typename Adaptor::Type* array = typedVector();
- for (unsigned i = start; i < end; ++i)
- array[i] = value;
-
- return true;
- }
-
void sort()
{
switch (Adaptor::typeValue) {
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h (203203 => 203204)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h 2016-07-14 00:15:03 UTC (rev 203204)
@@ -37,8 +37,6 @@
namespace JSC {
-static const char* typedArrayBufferHasBeenDetachedErrorMessage = "Underlying ArrayBuffer has been detached from the view";
-
template<typename Adaptor>
JSGenericTypedArrayView<Adaptor>::JSGenericTypedArrayView(
VM& vm, ConstructionContext& context)
@@ -325,9 +323,6 @@
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
- if (thisObject->isNeutered())
- return reject(exec, true, typedArrayBufferHasBeenDetachedErrorMessage);
-
// https://tc39.github.io/ecma262/#sec-integer-indexed-exotic-objects-set-p-v-receiver
// Ignore the receiver even if the receiver is altered to non base value.
// 9.4.5.5-2-b-i Return ? IntegerIndexedElementSet(O, numericIndex, V).
@@ -408,9 +403,6 @@
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
- if (thisObject->isNeutered())
- return reject(exec, true, typedArrayBufferHasBeenDetachedErrorMessage);
-
if (propertyName > MAX_ARRAY_INDEX) {
PutPropertySlot slot(JSValue(thisObject), shouldThrow);
return thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (203203 => 203204)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h 2016-07-14 00:15:03 UTC (rev 203204)
@@ -169,39 +169,6 @@
}
template<typename ViewClass>
-EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncFill(ExecState* exec)
-{
- // 22.2.3.8
- VM& vm = exec->vm();
- ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
- if (thisObject->isNeutered())
- return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
-
- JSValue valueToInsert = exec->argument(0);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- unsigned length = thisObject->length();
- unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 1, length);
- if (vm.exception())
- return encodedJSValue();
- unsigned end = argumentClampedIndexFromStartOrEnd(exec, 2, length, length);
- if (vm.exception())
- return encodedJSValue();
-
- if (thisObject->isNeutered())
- return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
-
- if (end < begin)
- return JSValue::encode(exec->thisValue());
-
- if (!thisObject->setRangeToValue(exec, begin, end, valueToInsert))
- return JSValue::encode(jsUndefined());
-
- return JSValue::encode(exec->thisValue());
-}
-
-template<typename ViewClass>
EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncIncludes(ExecState* exec)
{
ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
Modified: trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp (203203 => 203204)
--- trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp 2016-07-14 00:15:03 UTC (rev 203204)
@@ -114,14 +114,6 @@
CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncCopyWithin);
}
-static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncFill(ExecState* exec)
-{
- JSValue thisValue = exec->thisValue();
- if (!thisValue.isObject())
- return throwVMTypeError(exec, ASCIILiteral("Receiver should be a typed array view but was not an object"));
- CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncFill);
-}
-
static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncIncludes(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
@@ -267,8 +259,8 @@
JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("filter", typedArrayPrototypeFilterCodeGenerator, DontEnum);
JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort", typedArrayPrototypeSortCodeGenerator, DontEnum);
JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().entriesPublicName(), typedArrayPrototypeEntriesCodeGenerator, DontEnum);
- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("fill", typedArrayViewProtoFuncFill, DontEnum, 1);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("includes", typedArrayViewProtoFuncIncludes, DontEnum, 1);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("fill", typedArrayPrototypeFillCodeGenerator, DontEnum);
JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("find", typedArrayPrototypeFindCodeGenerator, DontEnum);
JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("findIndex", typedArrayPrototypeFindIndexCodeGenerator, DontEnum);
JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->forEach, typedArrayPrototypeForEachCodeGenerator, DontEnum);
Modified: trunk/Source/_javascript_Core/tests/stress/typedarray-fill.js (203203 => 203204)
--- trunk/Source/_javascript_Core/tests/stress/typedarray-fill.js 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-fill.js 2016-07-14 00:15:03 UTC (rev 203204)
@@ -32,4 +32,18 @@
shouldBeTrue("testPrototypeFunction('fill', '(4, NaN, 5)', [14, 15, 10, 13, 44], [4, 4, 4, 4, 4])");
shouldBeTrue("testPrototypeFunction('fill', '(4, -3, -2)', [14, 15, 10, 13, 44], [14, 15, 4, 13, 44])");
shouldBeTrue("testPrototypeFunction('fill', '(4, 5, 5)', [14, 15, 10, 13, 44], [14, 15, 10, 13, 44])");
+
+debug("4.0 Coercion Testing");
+for (constructor of typedArrays) {
+ count = 0;
+ let p = new Proxy({}, { get(target, name) {
+ count++;
+ return target[name];
+ }});
+ new constructor(10).fill(p);
+ shouldBeTrue("count === 40");
+}
+
+
+
finishJSTest();
Modified: trunk/Source/_javascript_Core/tests/stress/typedarray-functions-with-neutered.js (203203 => 203204)
--- trunk/Source/_javascript_Core/tests/stress/typedarray-functions-with-neutered.js 2016-07-14 00:12:58 UTC (rev 203203)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-functions-with-neutered.js 2016-07-14 00:15:03 UTC (rev 203204)
@@ -77,7 +77,7 @@
prototypeFunctions = [
{ func:proto.copyWithin, args:["prim", "prim", "prim"] },
{ func:proto.every, args:["func"] },
- { func:proto.fill, args:["ins", "prim", "prim"] },
+ { func:proto.fill, args:["prim", "prim", "prim"] },
{ func:proto.filter, args:["func"] },
{ func:proto.find, args:["func"] },
{ func:proto.findIndex, args:["func"] },
@@ -95,12 +95,14 @@
{ func:proto.subarray, args:["prim", "prim"] },
];
-function defaultForArg(arg)
+function defaultForArg(arg, argNum)
{
if (arg === "func")
- return () => { return 1; }
+ return () => { return argNum; }
+ if (arg === "array")
+ return [1,2];
- return 1;
+ return argNum;
}
function callWithArgs(func, array, args) {
@@ -127,34 +129,40 @@
if (arg === "na")
continue;
- let len = 10;
+ let array = new constructor(10);
if (arg === "func") {
- let array = new constructor(len);
callArgs[argNum] = () => {
transferArrayBuffer(array.buffer);
return func === array.every ? 1 : 0;
};
callWithArgs(func, array, callArgs);
- }
-
- if (arg === "prim") {
- let array = new constructor(len)
+ } else if (arg === "prim") {
callArgs[argNum] = { [Symbol.toPrimitive]() {
transferArrayBuffer(array.buffer);
+ return argNum;
+ } };
+ callWithArgs(func, array, callArgs);
+ } else if (arg === "array") {
+ callArgs[argNum] = new Array(4);
+ callArgs[argNum].fill(2);
+ let desc = { get: () => {
+ transferArrayBuffer(array.buffer);
return 1;
} };
+ Object.defineProperty(callArgs[argNum], 1, desc);
callWithArgs(func, array, callArgs);
- }
+ } else
+ throw new Error(arg);
}
}
function checkArguments({func, args}) {
for (constructor of typedArrays)
- checkArgumentsForType(func, args, constructor)
+ checkArgumentsForType(func, args, constructor);
}
-function test() {
+function test2() {
prototypeFunctions.forEach(checkArguments);
}
-test();
+test2();