author | Jan de Mooij <jdemooij@mozilla.com> |
Wed, 10 Feb 2021 11:22:59 +0000 | |
changeset 566799 | 03c71d1fa7f823e8bb23433503446d0fce37cff8 |
parent 566798 | 01813d1260e00a5597137f02e60c93b35d080d39 |
child 566800 | ce348dc698371692817127de918fe4e1e262dffb |
push id | 38190 |
push user | btara@mozilla.com |
push date | Wed, 10 Feb 2021 21:50:51 +0000 |
treeherder | mozilla-central@569826c0fd47 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | kmag |
bugs | 1674777 |
milestone | 87.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -1439,17 +1439,26 @@ bool XPCConvert::JSArray2Native(JSContex return false; } if (aEltType.Tag() != tag) { return false; } // Allocate the backing buffer before getting the view data in case // allocFixupLen can cause GCs. - uint32_t length = JS_GetTypedArrayLength(jsarray); + uint32_t length; + { + // nsTArray and code below uses uint32_t lengths, so reject large typed + // arrays. + size_t fullLength = JS_GetTypedArrayLength(jsarray); + if (fullLength > UINT32_MAX) { + return false; + } + length = uint32_t(fullLength); + } void* buf = allocFixupLen(&length); if (!buf) { return false; } // Get the backing memory buffer to copy out of. JS::AutoCheckCannotGC nogc; bool isShared = false;
--- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1222,18 +1222,21 @@ bool CallMethodHelper::GetArraySizeFromP MOZ_ASSERT(mMethodInfo->Param(argnum).IsOptional()); RootedObject arrayOrNull(mCallContext, &maybeArray.toObject()); bool isArray; bool ok = false; if (JS::IsArrayObject(mCallContext, maybeArray, &isArray) && isArray) { ok = JS::GetArrayLength(mCallContext, arrayOrNull, lengthp); } else if (JS_IsTypedArrayObject(&maybeArray.toObject())) { - *lengthp = JS_GetTypedArrayLength(&maybeArray.toObject()); - ok = true; + size_t len = JS_GetTypedArrayLength(&maybeArray.toObject()); + if (len <= UINT32_MAX) { + *lengthp = len; + ok = true; + } } if (!ok) { return Throw(NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY, mCallContext); } } *result = *lengthp;
--- a/js/xpconnect/tests/chrome/chrome.ini +++ b/js/xpconnect/tests/chrome/chrome.ini @@ -28,17 +28,18 @@ support-files = !/js/xpconnect/tests/mochitest/file_empty.html !/js/xpconnect/tests/mochitest/file_exnstack.html !/js/xpconnect/tests/mochitest/file_expandosharing.html !/js/xpconnect/tests/mochitest/file_nodelists.html !/js/xpconnect/tests/mochitest/file_evalInSandbox.html !/js/xpconnect/tests/mochitest/file_xrayic.html prefs = javascript.options.experimental.private_fields=true - + javascript.options.large_arraybuffers=true + [test_APIExposer.xhtml] [test_bug361111.xhtml] [test_bug448587.xhtml] [test_bug484459.xhtml] skip-if = os == 'win' || os == 'mac' || (os == 'linux' && !debug) # bug 1131110, 1255284 [test_bug500931.xhtml] [test_bug503926.xhtml] [test_bug533596.xhtml] @@ -113,11 +114,13 @@ skip-if = os == 'win' || os == 'mac' || [test_scripterror.html] [test_sharedChromeCompartment.html] [test_weakmap_keys_preserved.xhtml] [test_weakmap_keys_preserved2.xhtml] [test_weakref.xhtml] [test_windowProxyDeadWrapper.html] [test_wrappers.xhtml] [test_xrayic.xhtml] +[test_xrayLargeTypedArray.html] +skip-if = bits == 32 # Large ArrayBuffers not supported on 32-bit. [test_xrayToJS.xhtml] [test_bug1530146.html] support-files = file_bug1530146.html file_bug1530146_inner.html
new file mode 100644 --- /dev/null +++ b/js/xpconnect/tests/chrome/test_xrayLargeTypedArray.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1674777 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1674777</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://global/skin"/> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + +/** Test for Bug 1674777 **/ + +function go() { + SimpleTest.waitForExplicitFinish(); + + let win = document.getElementById('ifr').contentWindow; + + const nbytes = 3 * 1024 * 1024 * 1024; // 3 GB. + let tarray = new win.Int8Array(nbytes); + ok(Cu.isXrayWrapper(tarray), "Should be Xray"); + is(tarray.length, nbytes, "Length should match"); + is(tarray.byteLength, nbytes, "byteLength should match"); + + // Expect OOM when getting all property names. + let ex; + try { + Object.getOwnPropertyNames(tarray); + } catch (e) { + ex = e; + } + is(ex, "out of memory", "Expected OOM"); + + SimpleTest.finish(); +} + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1674777">Mozilla Bug 1674777</a> + +<iframe id="ifr" onload="go();" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html" /> + +</body> +</html>
--- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -925,23 +925,33 @@ bool JSXrayTraits::enumerateNames(JSCont } } for (size_t i = 0; i < props.length(); ++i) { JS_MarkCrossZoneId(cx, props[i]); } return true; } if (IsTypedArrayKey(key)) { - uint32_t length = JS_GetTypedArrayLength(target); + size_t length = JS_GetTypedArrayLength(target); // TypedArrays enumerate every indexed property in range, but // |length| is a getter that lives on the proto, like it should be. + + // Fail early if the typed array is enormous, because this will be very + // slow and will likely report OOM. This also means we don't need to + // handle indices greater than JSID_INT_MAX in the loop below. + static_assert(JSID_INT_MAX >= INT32_MAX); + if (length > INT32_MAX) { + JS_ReportOutOfMemory(cx); + return false; + } + if (!props.reserve(length)) { return false; } - for (int32_t i = 0; i <= int32_t(length - 1); ++i) { + for (int32_t i = 0; i < int32_t(length); ++i) { props.infallibleAppend(INT_TO_JSID(i)); } } else if (key == JSProto_Function) { if (!props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_LENGTH))) { return false; } if (!props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_NAME))) { return false;