Skip to content

Commit 703bb2b

Browse files
committed
Bug 1966355 - Part 19: Ensure immutable array buffers are rejected by WebIDL. r=webidl,saschanaz,edgar
WebIDL integration for immutable array buffers isn't yet defined, so for now disallow immutable array buffers and views to immutable array buffers. See also <tc39/proposal-immutable-arraybuffer#43>. Differential Revision: https://phabricator.services.mozilla.com/D249412
1 parent 770ac01 commit 703bb2b

File tree

5 files changed

+102
-0
lines changed

5 files changed

+102
-0
lines changed

dom/bindings/Codegen.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5860,6 +5860,13 @@ def onFailureIsResizable():
58605860
"%s" % (firstCap(sourceDescription), exceptionCode)
58615861
)
58625862

5863+
def onFailureIsImmutable():
5864+
desc = firstCap(sourceDescription)
5865+
return CGGeneric(
5866+
f'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_IMMUTABLE>("{desc}");\n'
5867+
f"{exceptionCode}"
5868+
)
5869+
58635870
def onFailureNotCallable(failureCode):
58645871
return CGGeneric(
58655872
failureCode
@@ -6897,11 +6904,13 @@ def incrementNestingLevel():
68976904
isSharedMethod = "JS::IsSharedArrayBufferObject"
68986905
isLargeMethod = "JS::IsLargeArrayBufferMaybeShared"
68996906
isResizableMethod = "JS::IsResizableArrayBufferMaybeShared"
6907+
isImmutableMethod = "JS::IsImmutableArrayBufferMaybeShared"
69006908
else:
69016909
assert type.isArrayBufferView() or type.isTypedArray()
69026910
isSharedMethod = "JS::IsArrayBufferViewShared"
69036911
isLargeMethod = "JS::IsLargeArrayBufferView"
69046912
isResizableMethod = "JS::IsResizableArrayBufferView"
6913+
isImmutableMethod = "JS::IsImmutableArrayBufferView"
69056914
if not isAllowShared:
69066915
template += fill(
69076916
"""
@@ -6939,6 +6948,18 @@ def incrementNestingLevel():
69396948
objRef=objRef,
69406949
badType=onFailureIsResizable().define(),
69416950
)
6951+
# For now reject immutable ArrayBuffers. Supporting this will
6952+
# require changing dom::TypedArray and consumers.
6953+
template += fill(
6954+
"""
6955+
if (${isImmutableMethod}(${objRef}.Obj())) {
6956+
$*{badType}
6957+
}
6958+
""",
6959+
isImmutableMethod=isImmutableMethod,
6960+
objRef=objRef,
6961+
badType=onFailureIsImmutable().define(),
6962+
)
69426963
template = wrapObjectTemplate(
69436964
template, type, "${declName}.SetNull();\n", failureCode
69446965
)

dom/bindings/Errors.msg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ MSG_DEF(MSG_SW_SCRIPT_THREW, 3, true, JSEXN_TYPEERR, "{0}ServiceWorker script at
7575
MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 2, true, JSEXN_TYPEERR, "{0}{1} can't be a SharedArrayBuffer or an ArrayBufferView backed by a SharedArrayBuffer")
7676
MSG_DEF(MSG_TYPEDARRAY_IS_LARGE, 2, true, JSEXN_TYPEERR, "{0}{1} can't be an ArrayBuffer or an ArrayBufferView larger than 2 GB")
7777
MSG_DEF(MSG_TYPEDARRAY_IS_RESIZABLE, 2, true, JSEXN_TYPEERR, "{0}{1} can't be a resizable ArrayBuffer or ArrayBufferView")
78+
MSG_DEF(MSG_TYPEDARRAY_IS_IMMUTABLE, 2, true, JSEXN_TYPEERR, "{0}{1} can't be an immutable ArrayBuffer or ArrayBufferView")
7879
MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 4, true, JSEXN_TYPEERR, "{0}Cache got {1} response with bad status {2} while trying to add request {3}")
7980
MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 3, true, JSEXN_TYPEERR, "{0}Failed to update the ServiceWorker for scope {1} because the registration has been {2} since the update was scheduled.")
8081
MSG_DEF(MSG_INVALID_DURATION_ERROR, 2, true, JSEXN_TYPEERR, "{0}Invalid duration '{1}'.")

dom/bindings/TypedArray.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,9 @@ struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
711711
MOZ_RELEASE_ASSERT(
712712
!ArrayT::fromObject(mImplObj).isResizable(),
713713
"Bindings must have checked ArrayBuffer{View} is non-resizable");
714+
MOZ_RELEASE_ASSERT(
715+
!ArrayT::fromObject(mImplObj).isImmutable(),
716+
"Bindings must have checked ArrayBuffer{View} is mutable");
714717

715718
// Intentionally return a pointer and length that escape from a nogc region.
716719
// Private so it can only be used in very limited situations.

dom/bindings/test/mochitest.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ support-files = [
1010
]
1111
prefs = [
1212
"javascript.options.large_arraybuffers=true",
13+
"javascript.options.experimental.arraybuffer_immutable=true",
1314
]
1415

1516
["test_ByteString.html"]
@@ -180,6 +181,12 @@ skip-if = [
180181
"!nightly_build", # Bug 1670026
181182
]
182183

184+
["test_immutable_arraybufferview.html"]
185+
skip-if = [
186+
"!debug",
187+
"!nightly_build", # Bug 1952253
188+
]
189+
183190
["test_returnUnion.html"]
184191
skip-if = ["!debug"]
185192

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<!DOCTYPE HTML>
2+
<html>
3+
<!--
4+
https://bugzilla.mozilla.org/show_bug.cgi?id=1952253
5+
-->
6+
<head>
7+
<meta charset="utf-8">
8+
<title>Test for immutable ArrayBufferViews</title>
9+
<script src="/tests/SimpleTest/SimpleTest.js"></script>
10+
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
11+
</head>
12+
<body>
13+
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1952253">Mozilla Bug 1952253</a>
14+
<p id="display"></p>
15+
<div id="content" style="display: none">
16+
17+
</div>
18+
<pre id="test">
19+
</pre>
20+
<script type="application/javascript">
21+
/* global TestFunctions */
22+
23+
function checkThrowsImmutable(f) {
24+
let ex;
25+
try{
26+
f();
27+
ok(false, "Should have thrown!");
28+
} catch (e) {
29+
ex = e;
30+
}
31+
ok(ex.toString().includes("immutable ArrayBuffer or ArrayBufferView"), "Got exception: " + ex);
32+
}
33+
34+
add_task(async function test_immutable_arraybuffer_views() {
35+
await SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]});
36+
let test = new TestFunctions();
37+
38+
let ab = new ArrayBuffer(16).transferToImmutable();
39+
checkThrowsImmutable(() => test.testNotAllowShared(ab));
40+
checkThrowsImmutable(() => test.testAllowShared(ab));
41+
checkThrowsImmutable(() => test.testDictWithAllowShared({arrayBuffer: ab}));
42+
checkThrowsImmutable(() => test.testUnionOfBufferSource(ab));
43+
checkThrowsImmutable(() => { test.arrayBuffer = ab; });
44+
checkThrowsImmutable(() => { test.allowSharedArrayBuffer = ab; });
45+
checkThrowsImmutable(() => { test.sequenceOfArrayBuffer = [ab]; });
46+
checkThrowsImmutable(() => { test.sequenceOfAllowSharedArrayBuffer = [ab]; });
47+
48+
let ta = new Int8Array(ab);
49+
checkThrowsImmutable(() => test.testNotAllowShared(ta));
50+
checkThrowsImmutable(() => test.testAllowShared(ta));
51+
checkThrowsImmutable(() => test.testDictWithAllowShared({arrayBufferView: ta}));
52+
checkThrowsImmutable(() => test.testUnionOfBufferSource(ta));
53+
checkThrowsImmutable(() => { test.arrayBufferView = ta; });
54+
checkThrowsImmutable(() => { test.allowSharedArrayBufferView = ta; });
55+
checkThrowsImmutable(() => { test.sequenceOfArrayBufferView = [ta]; });
56+
checkThrowsImmutable(() => { test.sequenceOfAllowSharedArrayBufferView = [ta]; });
57+
58+
let dv = new DataView(ab);
59+
checkThrowsImmutable(() => test.testNotAllowShared(dv));
60+
checkThrowsImmutable(() => test.testAllowShared(dv));
61+
checkThrowsImmutable(() => test.testDictWithAllowShared({arrayBufferView: dv}));
62+
checkThrowsImmutable(() => test.testUnionOfBufferSource(dv));
63+
checkThrowsImmutable(() => { test.arrayBufferView = dv; });
64+
checkThrowsImmutable(() => { test.allowSharedArrayBufferView = dv; });
65+
checkThrowsImmutable(() => { test.sequenceOfArrayBufferView = [dv]; });
66+
checkThrowsImmutable(() => { test.sequenceOfAllowSharedArrayBufferView = [dv]; });
67+
});
68+
</script>
69+
</body>
70+
</html>

0 commit comments

Comments
 (0)