mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-03 13:57:31 +09:00
Handle same-compartment wrappers in TypedArray methods.
CallTypedArrayMethodIfWrapped (and the CallNonGeneric machinery throughout the engine) unwraps the `this` argument, but the other arguments are only rewrapped for the target compartment. The pattern being used before this patch to get the length of a TypedArray or possible TypedArray wrapper is: `callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength")` The first `O` is the `this` value and the second is an argument. If `O` is a cross-compartment wrapper, this works fine. The first `O` is unwrapped, revealing the actual TypedArray object; the second `O` is rewrapped for that TypedArray's compartment, producing the same TypedArray. However, if `O` is a same-compartment wrapper, this doesn't work. The first `O` is unwrapped, revealing the actual TypedArray object in the same compartment; rewrapping the other `O` does nothing to it, since it is already an object in the target compartment. Thus TypedArrayLength receives a `this` value that's an unwrapped TypedArray, but an argument that is still a wrapper. The fix is to have CallTypedArrayMethodIfWrapped targets only expect `this` to be an unwrapped TypedArray.
This commit is contained in:
parent
df053b80f5
commit
04caaa6539
3 changed files with 55 additions and 40 deletions
|
|
@ -35,6 +35,10 @@ function IsDetachedBuffer(buffer) {
|
||||||
return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
|
return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TypedArrayLengthMethod() {
|
||||||
|
return TypedArrayLength(this);
|
||||||
|
}
|
||||||
|
|
||||||
function GetAttachedArrayBuffer(tarray) {
|
function GetAttachedArrayBuffer(tarray) {
|
||||||
var buffer = ViewedArrayBufferIfReified(tarray);
|
var buffer = ViewedArrayBufferIfReified(tarray);
|
||||||
if (IsDetachedBuffer(buffer))
|
if (IsDetachedBuffer(buffer))
|
||||||
|
|
@ -42,6 +46,10 @@ function GetAttachedArrayBuffer(tarray) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetAttachedArrayBufferMethod() {
|
||||||
|
return GetAttachedArrayBuffer(this);
|
||||||
|
}
|
||||||
|
|
||||||
// A function which ensures that the argument is either a typed array or a
|
// A function which ensures that the argument is either a typed array or a
|
||||||
// cross-compartment wrapper for a typed array and that the typed array involved
|
// cross-compartment wrapper for a typed array and that the typed array involved
|
||||||
// has an attached array buffer. If one of those conditions doesn't hold (wrong
|
// has an attached array buffer. If one of those conditions doesn't hold (wrong
|
||||||
|
|
@ -54,10 +62,7 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a bit hacky but gets the job done: the first `arg` is used to
|
callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
|
||||||
// test for a wrapped typed array, the second as an argument to
|
|
||||||
// GetAttachedArrayBuffer.
|
|
||||||
callFunction(CallTypedArrayMethodIfWrapped, arg, arg, "GetAttachedArrayBuffer");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,8 +103,8 @@ function TypedArrayCreateWithLength(constructor, length) {
|
||||||
if (isTypedArray) {
|
if (isTypedArray) {
|
||||||
len = TypedArrayLength(newTypedArray);
|
len = TypedArrayLength(newTypedArray);
|
||||||
} else {
|
} else {
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray, newTypedArray,
|
len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray,
|
||||||
"TypedArrayLength");
|
"TypedArrayLengthMethod");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < length)
|
if (len < length)
|
||||||
|
|
@ -259,15 +264,14 @@ function TypedArrayEvery(callbackfn/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Steps 3-5.
|
// Steps 3-5.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -348,15 +352,14 @@ function TypedArrayFilter(callbackfn/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -410,15 +413,14 @@ function TypedArrayFind(predicate/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Steps 3-5.
|
// Steps 3-5.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -452,15 +454,14 @@ function TypedArrayFindIndex(predicate/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Steps 3-5.
|
// Steps 3-5.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -492,15 +493,14 @@ function TypedArrayForEach(callbackfn/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Step 3-4.
|
// Step 3-4.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -686,15 +686,14 @@ function TypedArrayMap(callbackfn/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -730,15 +729,14 @@ function TypedArrayReduce(callbackfn/*, initialValue*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Steps 3-5.
|
// Steps 3-5.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -776,15 +774,14 @@ function TypedArrayReduceRight(callbackfn/*, initialValue*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Steps 3-5.
|
// Steps 3-5.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -1034,15 +1031,14 @@ function TypedArraySome(callbackfn/*, thisArg*/) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Steps 3-5.
|
// Steps 3-5.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(O);
|
len = TypedArrayLength(O);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0)
|
||||||
|
|
@ -1137,7 +1133,7 @@ function TypedArraySort(comparefn) {
|
||||||
if (isTypedArray) {
|
if (isTypedArray) {
|
||||||
buffer = GetAttachedArrayBuffer(obj);
|
buffer = GetAttachedArrayBuffer(obj);
|
||||||
} else {
|
} else {
|
||||||
buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "GetAttachedArrayBuffer");
|
buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, "GetAttachedArrayBufferMethod");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
|
@ -1145,7 +1141,7 @@ function TypedArraySort(comparefn) {
|
||||||
if (isTypedArray) {
|
if (isTypedArray) {
|
||||||
len = TypedArrayLength(obj);
|
len = TypedArrayLength(obj);
|
||||||
} else {
|
} else {
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, obj, "TypedArrayLengthMethod");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comparefn === undefined) {
|
if (comparefn === undefined) {
|
||||||
|
|
@ -1181,8 +1177,8 @@ function TypedArraySort(comparefn) {
|
||||||
if (isTypedArray) {
|
if (isTypedArray) {
|
||||||
buffer = GetAttachedArrayBuffer(obj);
|
buffer = GetAttachedArrayBuffer(obj);
|
||||||
} else {
|
} else {
|
||||||
buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj,
|
buffer = callFunction(CallTypedArrayMethodIfWrapped, obj,
|
||||||
"GetAttachedArrayBuffer");
|
"GetAttachedArrayBufferMethod");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var bufferDetached;
|
var bufferDetached;
|
||||||
|
|
@ -1217,15 +1213,14 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) {
|
||||||
// We want to make sure that we have an attached buffer, per spec prose.
|
// We want to make sure that we have an attached buffer, per spec prose.
|
||||||
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(array);
|
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(array);
|
||||||
|
|
||||||
// If we got here, `this` is either a typed array or a cross-compartment
|
// If we got here, `this` is either a typed array or a wrapper for one.
|
||||||
// wrapper for one.
|
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
var len;
|
var len;
|
||||||
if (isTypedArray)
|
if (isTypedArray)
|
||||||
len = TypedArrayLength(array);
|
len = TypedArrayLength(array);
|
||||||
else
|
else
|
||||||
len = callFunction(CallTypedArrayMethodIfWrapped, array, array, "TypedArrayLength");
|
len = callFunction(CallTypedArrayMethodIfWrapped, array, "TypedArrayLengthMethod");
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
if (len === 0)
|
if (len === 0)
|
||||||
|
|
|
||||||
1
js/src/jit-test/tests/proxy/testWrapWithProtoIter.js
Normal file
1
js/src/jit-test/tests/proxy/testWrapWithProtoIter.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[...wrapWithProto(new Int8Array(), new Int8Array())]
|
||||||
19
js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js
Normal file
19
js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
let a = wrapWithProto(new Int8Array([1, 3, 5, 6, 9]), new Int8Array());
|
||||||
|
|
||||||
|
assertEq([...a].toString(), "1,3,5,6,9");
|
||||||
|
assertEq(a.every(e => e < 100), true);
|
||||||
|
assertEq(a.filter(e => e % 2 == 1).toString(), "1,3,5,9");
|
||||||
|
assertEq(a.find(e => e > 3), 5);
|
||||||
|
assertEq(a.findIndex(e => e % 2 == 0), 3);
|
||||||
|
assertEq(a.map(e => e * 10).toString(), "10,30,50,60,90");
|
||||||
|
assertEq(a.reduce((a, b) => a + b, ""), "13569");
|
||||||
|
assertEq(a.reduceRight((acc, e) => "(" + e + acc + ")", ""), "(1(3(5(6(9)))))");
|
||||||
|
assertEq(a.some(e => e % 2 == 0), true);
|
||||||
|
|
||||||
|
let s = "";
|
||||||
|
assertEq(a.forEach(e => s += e), undefined);
|
||||||
|
assertEq(s, "13569");
|
||||||
|
|
||||||
|
a.sort((a, b) => b - a);
|
||||||
|
assertEq(a.toString(), "9,6,5,3,1");
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue