ma1 pushed to branch mullvad-browser-140.17.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
-
02322e29
by James Teh at 2026-09-28T10:43:54+02:00
-
76943803
by Rob Wu at 2026-09-28T10:43:58+02:00
-
357553c1
by Marco Bonardo at 2026-09-28T10:44:03+02:00
-
0060fe36
by Tom Schuster at 2026-09-28T10:44:07+02:00
-
855edaae
by Leo Tenenbaum at 2026-09-28T10:44:12+02:00
-
ba101997
by Iain Ireland at 2026-09-28T10:44:16+02:00
-
59434ea5
by Iain Ireland at 2026-09-28T10:44:19+02:00
14 changed files:
- accessible/base/DocManager.cpp
- accessible/ipc/DocAccessibleParent.cpp
- browser/components/places/content/controller.js
- browser/components/places/tests/browser/browser_toolbar_drop_bookmarklet.js
- browser/components/places/tests/browser/browser_toolbar_drop_multiple_with_bookmarklet.js
- dom/base/nsContentUtils.cpp
- dom/script/ScriptLoader.cpp
- dom/security/nsContentSecurityUtils.cpp
- js/src/jit/BaselineIC.cpp
- js/src/jit/CacheIR.cpp
- js/src/jit/CacheIRWriter.h
- js/src/vm/PortableBaselineInterpret.cpp
- toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html
- toolkit/components/extensions/webrequest/WebRequestUpload.sys.mjs
Changes:
| ... | ... | @@ -31,6 +31,10 @@ |
| 31 | 31 | #include "nsCoreUtils.h"
|
| 32 | 32 | #include "xpcAccessibleDocument.h"
|
| 33 | 33 | |
| 34 | +#if defined(ANDROID)
|
|
| 35 | +# include "mozilla/Monitor.h"
|
|
| 36 | +#endif
|
|
| 37 | + |
|
| 34 | 38 | using namespace mozilla;
|
| 35 | 39 | using namespace mozilla::a11y;
|
| 36 | 40 | using namespace mozilla::dom;
|
| ... | ... | @@ -195,6 +199,18 @@ void DocManager::Shutdown() { |
| 195 | 199 | }
|
| 196 | 200 | |
| 197 | 201 | ClearDocCache();
|
| 202 | + // Even though remote documents aren't strictly managed by this DocManager
|
|
| 203 | + // instance, destroy them now because they might depend on platform specific
|
|
| 204 | + // state which is about to be torn down by PlatformShutdown. Iterate the array
|
|
| 205 | + // backwards because destroying the document removes it from this array.
|
|
| 206 | + if (sRemoteDocuments) {
|
|
| 207 | +#if defined(ANDROID)
|
|
| 208 | + MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
|
|
| 209 | +#endif
|
|
| 210 | + for (size_t i = sRemoteDocuments->Length(); i-- > 0;) {
|
|
| 211 | + (*sRemoteDocuments)[i]->Destroy();
|
|
| 212 | + }
|
|
| 213 | + }
|
|
| 198 | 214 | }
|
| 199 | 215 | |
| 200 | 216 | ////////////////////////////////////////////////////////////////////////////////
|
| ... | ... | @@ -1241,15 +1241,14 @@ void DocAccessibleParent::MaybeInitWindowEmulation() { |
| 1241 | 1241 | isActive = browserParent->GetDocShellIsActive();
|
| 1242 | 1242 | }
|
| 1243 | 1243 | |
| 1244 | - // onCreate is guaranteed to be called synchronously by
|
|
| 1245 | - // nsWinUtils::CreateNativeWindow, so this reference isn't really necessary.
|
|
| 1246 | - // However, static analysis complains without it.
|
|
| 1247 | 1244 | RefPtr<DocAccessibleParent> thisRef = this;
|
| 1248 | - nsWinUtils::NativeWindowCreateProc onCreate([thisRef](HWND aHwnd) -> void {
|
|
| 1249 | - ::SetPropW(aHwnd, kPropNameDocAccParent,
|
|
| 1250 | - reinterpret_cast<HANDLE>(thisRef.get()));
|
|
| 1251 | - thisRef->SetEmulatedWindowHandle(aHwnd);
|
|
| 1252 | - });
|
|
| 1245 | + nsWinUtils::NativeWindowCreateProc onCreate(
|
|
| 1246 | + [thisRef](HWND aHwnd) mutable -> void {
|
|
| 1247 | + thisRef->SetEmulatedWindowHandle(aHwnd);
|
|
| 1248 | + HANDLE val;
|
|
| 1249 | + thisRef.forget(&val); // Release in SetEmulatedWindowHandle.
|
|
| 1250 | + ::SetPropW(aHwnd, kPropNameDocAccParent, val);
|
|
| 1251 | + });
|
|
| 1253 | 1252 | |
| 1254 | 1253 | HWND parentWnd = reinterpret_cast<HWND>(rootDocument->GetNativeWindow());
|
| 1255 | 1254 | DebugOnly<HWND> hWnd = nsWinUtils::CreateNativeWindow(
|
| ... | ... | @@ -1261,6 +1260,7 @@ void DocAccessibleParent::MaybeInitWindowEmulation() { |
| 1261 | 1260 | void DocAccessibleParent::SetEmulatedWindowHandle(HWND aWindowHandle) {
|
| 1262 | 1261 | if (!aWindowHandle && mEmulatedWindowHandle && IsTopLevel()) {
|
| 1263 | 1262 | ::DestroyWindow(mEmulatedWindowHandle);
|
| 1263 | + Release(); // AddRef in MaybeInitWindowEmulation.
|
|
| 1264 | 1264 | }
|
| 1265 | 1265 | mEmulatedWindowHandle = aWindowHandle;
|
| 1266 | 1266 | }
|
| ... | ... | @@ -1609,7 +1609,7 @@ var PlacesControllerDragHelper = { |
| 1609 | 1609 | if (
|
| 1610 | 1610 | !flavor.startsWith("text/x-moz-place") &&
|
| 1611 | 1611 | (validNodes.length > 1 || dropCount > 1) &&
|
| 1612 | - validNodes.some(n => n.uri?.startsWith("javascript:"))
|
|
| 1612 | + validNodes.some(n => URL.parse(n.uri)?.protocol === "javascript:")
|
|
| 1613 | 1613 | ) {
|
| 1614 | 1614 | return false;
|
| 1615 | 1615 | }
|
| ... | ... | @@ -1686,18 +1686,14 @@ var PlacesControllerDragHelper = { |
| 1686 | 1686 | if (
|
| 1687 | 1687 | externalDrag &&
|
| 1688 | 1688 | (nodes.length > 1 || dropCount > 1) &&
|
| 1689 | - nodes.some(n => n.uri?.startsWith("javascript:"))
|
|
| 1689 | + nodes.some(n => URL.parse(n.uri)?.protocol === "javascript:")
|
|
| 1690 | 1690 | ) {
|
| 1691 | 1691 | throw new Error("Javascript bookmarklet passed with uris");
|
| 1692 | 1692 | }
|
| 1693 | 1693 | |
| 1694 | 1694 | // If a single javascript url is being dropped from the urlbar or an external source,
|
| 1695 | 1695 | // show the bookmark dialog as a speedbump protection against malicious cases.
|
| 1696 | - if (
|
|
| 1697 | - nodes.length == 1 &&
|
|
| 1698 | - externalDrag &&
|
|
| 1699 | - nodes[0].uri?.startsWith("javascript")
|
|
| 1700 | - ) {
|
|
| 1696 | + if (nodes.length == 1 && externalDrag) {
|
|
| 1701 | 1697 | let uri;
|
| 1702 | 1698 | try {
|
| 1703 | 1699 | uri = Services.io.newURI(nodes[0].uri);
|
| ... | ... | @@ -1705,7 +1701,7 @@ var PlacesControllerDragHelper = { |
| 1705 | 1701 | // Invalid uri, we skip this code and the entry will be discarded later.
|
| 1706 | 1702 | }
|
| 1707 | 1703 | |
| 1708 | - if (uri) {
|
|
| 1704 | + if (uri?.scheme === "javascript") {
|
|
| 1709 | 1705 | let bookmarkGuid = await PlacesUIUtils.showBookmarkDialog(
|
| 1710 | 1706 | {
|
| 1711 | 1707 | action: "add",
|
| ... | ... | @@ -9,6 +9,7 @@ const sandbox = sinon.createSandbox(); |
| 9 | 9 | const URL1 = "https://example.com/1/";
|
| 10 | 10 | const URL2 = "https://example.com/2/";
|
| 11 | 11 | const BOOKMARKLET_URL = `javascript: (() => {alert('Hello, World!');})();`;
|
| 12 | +const BOOKMARKLET_URL_MIXED_CASE = `JavaScript: (() => {})();`;
|
|
| 12 | 13 | let bookmarks;
|
| 13 | 14 | |
| 14 | 15 | registerCleanupFunction(async function () {
|
| ... | ... | @@ -34,12 +35,18 @@ add_task(async function test() { |
| 34 | 35 | Assert.ok(placesItems, "PlacesToolbarItems should not be null");
|
| 35 | 36 | |
| 36 | 37 | /**
|
| 37 | - * Simulates a drop of a bookmarklet URI onto the bookmarks bar.
|
|
| 38 | + * Simulates a drop of a bookmarklet URI onto the bookmarks bar and verifies
|
|
| 39 | + * the speedbump dialog appears.
|
|
| 38 | 40 | *
|
| 39 | 41 | * @param {string} aEffect
|
| 40 | 42 | * The effect to use for the drop operation: move, copy, or link.
|
| 43 | + * @param {string} aBookmarkletUrl
|
|
| 44 | + * The bookmarklet URL to be dropped onto the bookmarks bar.
|
|
| 41 | 45 | */
|
| 42 | - let simulateDragDrop = async function (aEffect) {
|
|
| 46 | + let simulateBookmarkletDragDrop = async function (
|
|
| 47 | + aEffect,
|
|
| 48 | + aBookmarkletUrl = BOOKMARKLET_URL
|
|
| 49 | + ) {
|
|
| 43 | 50 | info("Simulates drag/drop of a new javascript:URL to the bookmarks");
|
| 44 | 51 | await withBookmarksDialog(
|
| 45 | 52 | true,
|
| ... | ... | @@ -47,7 +54,7 @@ add_task(async function test() { |
| 47 | 54 | EventUtils.synthesizeDrop(
|
| 48 | 55 | toolbar,
|
| 49 | 56 | placesItems,
|
| 50 | - [[{ type: "text/x-moz-url", data: BOOKMARKLET_URL }]],
|
|
| 57 | + [[{ type: "text/x-moz-url", data: aBookmarkletUrl }]],
|
|
| 51 | 58 | aEffect,
|
| 52 | 59 | window
|
| 53 | 60 | );
|
| ... | ... | @@ -61,11 +68,21 @@ add_task(async function test() { |
| 61 | 68 | |
| 62 | 69 | Assert.equal(
|
| 63 | 70 | location,
|
| 64 | - BOOKMARKLET_URL,
|
|
| 71 | + aBookmarkletUrl.trim().replace(/^javascript/i, "javascript"),
|
|
| 65 | 72 | "Should have opened the ShowBookmarksDialog with the correct bookmarklet url to be bookmarked"
|
| 66 | 73 | );
|
| 67 | 74 | }
|
| 68 | 75 | );
|
| 76 | + };
|
|
| 77 | + |
|
| 78 | + for (let effect of ["copy", "link"]) {
|
|
| 79 | + for (let bookmarkletUrl of [
|
|
| 80 | + BOOKMARKLET_URL,
|
|
| 81 | + BOOKMARKLET_URL_MIXED_CASE,
|
|
| 82 | + ` javascript: (() => {})();`,
|
|
| 83 | + ]) {
|
|
| 84 | + await simulateBookmarkletDragDrop(effect, bookmarkletUrl);
|
|
| 85 | + }
|
|
| 69 | 86 | |
| 70 | 87 | info("Simulates drag/drop of a new URL to the bookmarks");
|
| 71 | 88 | let spy = sandbox
|
| ... | ... | @@ -81,18 +98,13 @@ add_task(async function test() { |
| 81 | 98 | toolbar,
|
| 82 | 99 | placesItems,
|
| 83 | 100 | [[{ type: "text/x-moz-url", data: URL1 }]],
|
| 84 | - aEffect,
|
|
| 101 | + effect,
|
|
| 85 | 102 | window
|
| 86 | 103 | );
|
| 87 | 104 | |
| 88 | 105 | await promise;
|
| 89 | 106 | Assert.ok(spy.notCalled, "ShowBookmarksDialog on drop not called for url");
|
| 90 | 107 | sandbox.restore();
|
| 91 | - };
|
|
| 92 | - |
|
| 93 | - let effects = ["copy", "link"];
|
|
| 94 | - for (let effect of effects) {
|
|
| 95 | - await simulateDragDrop(effect);
|
|
| 96 | 108 | }
|
| 97 | 109 | |
| 98 | 110 | info("Move of existing bookmark / bookmarklet on toolbar");
|
| ... | ... | @@ -18,12 +18,12 @@ add_task(async function test() { |
| 18 | 18 | // matter because we will set its data, effect, and mimeType manually.
|
| 19 | 19 | let placesItems = document.getElementById("PlacesToolbarItems");
|
| 20 | 20 | Assert.ok(placesItems, "PlacesToolbarItems should not be null");
|
| 21 | - let simulateDragDrop = async function (aEffect, aMimeType) {
|
|
| 22 | - let urls = [
|
|
| 23 | - "https://example.com/1/",
|
|
| 24 | - `javascript: (() => {alert('Hello, World!');})();`,
|
|
| 25 | - "https://example.com/2/",
|
|
| 26 | - ];
|
|
| 21 | + let simulateDragDrop = async function (
|
|
| 22 | + aEffect,
|
|
| 23 | + aMimeType,
|
|
| 24 | + aJsUrl = `javascript: (() => {alert('Hello, World!');})();`
|
|
| 25 | + ) {
|
|
| 26 | + let urls = ["https://example.com/1/", aJsUrl, "https://example.com/2/"];
|
|
| 27 | 27 | |
| 28 | 28 | let data = urls.map(spec => spec + "\n" + spec).join("\n");
|
| 29 | 29 | |
| ... | ... | @@ -43,8 +43,13 @@ add_task(async function test() { |
| 43 | 43 | |
| 44 | 44 | // Simulate a bookmark drop for all of the mime types and effects.
|
| 45 | 45 | let mimeType = ["text/x-moz-url"];
|
| 46 | - let effects = ["copy", "link"];
|
|
| 47 | - for (let effect of effects) {
|
|
| 48 | - await simulateDragDrop(effect, mimeType);
|
|
| 46 | + for (let effect of ["copy", "link"]) {
|
|
| 47 | + for (let jsUrl of [
|
|
| 48 | + `javascript: (() => {alert('Hello, World!');})();`,
|
|
| 49 | + `JavaScript: (() => {})();`,
|
|
| 50 | + ` javascript: (() => {})();`,
|
|
| 51 | + ]) {
|
|
| 52 | + await simulateDragDrop(effect, mimeType, jsUrl);
|
|
| 53 | + }
|
|
| 49 | 54 | }
|
| 50 | 55 | }); |
| ... | ... | @@ -5635,9 +5635,10 @@ void nsContentUtils::RequestFrameFocus(Element& aFrameElement, bool aCanRaise, |
| 5635 | 5635 | RefPtr<Element> target = &aFrameElement;
|
| 5636 | 5636 | bool defaultAction = true;
|
| 5637 | 5637 | if (aCanRaise) {
|
| 5638 | - DispatchEventOnlyToChrome(target->OwnerDoc(), target,
|
|
| 5639 | - u"framefocusrequested"_ns, CanBubble::eYes,
|
|
| 5640 | - Cancelable::eYes, &defaultAction);
|
|
| 5638 | + RefPtr<Document> doc = target->OwnerDoc();
|
|
| 5639 | + DispatchEventOnlyToChrome(doc, target, u"framefocusrequested"_ns,
|
|
| 5640 | + CanBubble::eYes, Cancelable::eYes,
|
|
| 5641 | + &defaultAction);
|
|
| 5641 | 5642 | }
|
| 5642 | 5643 | if (!defaultAction) {
|
| 5643 | 5644 | return;
|
| ... | ... | @@ -240,27 +240,27 @@ ScriptLoader::~ScriptLoader() { |
| 240 | 240 | FireScriptAvailable(NS_ERROR_ABORT, mParserBlockingRequest);
|
| 241 | 241 | }
|
| 242 | 242 | |
| 243 | - for (ScriptLoadRequest* req = mXSLTRequests.getFirst(); req;
|
|
| 243 | + for (RefPtr<ScriptLoadRequest> req = mXSLTRequests.getFirst(); req;
|
|
| 244 | 244 | req = req->getNext()) {
|
| 245 | 245 | FireScriptAvailable(NS_ERROR_ABORT, req);
|
| 246 | 246 | }
|
| 247 | 247 | |
| 248 | - for (ScriptLoadRequest* req = mDeferRequests.getFirst(); req;
|
|
| 248 | + for (RefPtr<ScriptLoadRequest> req = mDeferRequests.getFirst(); req;
|
|
| 249 | 249 | req = req->getNext()) {
|
| 250 | 250 | FireScriptAvailable(NS_ERROR_ABORT, req);
|
| 251 | 251 | }
|
| 252 | 252 | |
| 253 | - for (ScriptLoadRequest* req = mLoadingAsyncRequests.getFirst(); req;
|
|
| 253 | + for (RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.getFirst(); req;
|
|
| 254 | 254 | req = req->getNext()) {
|
| 255 | 255 | FireScriptAvailable(NS_ERROR_ABORT, req);
|
| 256 | 256 | }
|
| 257 | 257 | |
| 258 | - for (ScriptLoadRequest* req = mLoadedAsyncRequests.getFirst(); req;
|
|
| 258 | + for (RefPtr<ScriptLoadRequest> req = mLoadedAsyncRequests.getFirst(); req;
|
|
| 259 | 259 | req = req->getNext()) {
|
| 260 | 260 | FireScriptAvailable(NS_ERROR_ABORT, req);
|
| 261 | 261 | }
|
| 262 | 262 | |
| 263 | - for (ScriptLoadRequest* req =
|
|
| 263 | + for (RefPtr<ScriptLoadRequest> req =
|
|
| 264 | 264 | mNonAsyncExternalScriptInsertedRequests.getFirst();
|
| 265 | 265 | req; req = req->getNext()) {
|
| 266 | 266 | FireScriptAvailable(NS_ERROR_ABORT, req);
|
| ... | ... | @@ -1176,8 +1176,9 @@ nsString nsContentSecurityUtils::GetIsElementNonceableNonce( |
| 1176 | 1176 | // element’s attribute list:
|
| 1177 | 1177 | if (nsCOMPtr<nsIScriptElement> script =
|
| 1178 | 1178 | do_QueryInterface(const_cast<Element*>(&aElement))) {
|
| 1179 | - auto containsScriptOrStyle = [](const nsAString& aStr) {
|
|
| 1180 | - return aStr.LowerCaseFindASCII("<script") != kNotFound ||
|
|
| 1179 | + auto containsLinkScriptOrStyle = [](const nsAString& aStr) {
|
|
| 1180 | + return aStr.LowerCaseFindASCII("<link") != kNotFound ||
|
|
| 1181 | + aStr.LowerCaseFindASCII("<script") != kNotFound ||
|
|
| 1181 | 1182 | aStr.LowerCaseFindASCII("<style") != kNotFound;
|
| 1182 | 1183 | };
|
| 1183 | 1184 | |
| ... | ... | @@ -1185,21 +1186,21 @@ nsString nsContentSecurityUtils::GetIsElementNonceableNonce( |
| 1185 | 1186 | uint32_t i = 0;
|
| 1186 | 1187 | while (BorrowedAttrInfo info = aElement.GetAttrInfoAt(i++)) {
|
| 1187 | 1188 | // Step 2.1. If attribute’s name contains an ASCII case-insensitive match
|
| 1188 | - // for "<script" or "<style", return "Not Nonceable".
|
|
| 1189 | + // for "<link", <script" or "<style", return "Not Nonceable".
|
|
| 1189 | 1190 | const nsAttrName* name = info.mName;
|
| 1190 | 1191 | if (nsAtom* prefix = name->GetPrefix()) {
|
| 1191 | - if (containsScriptOrStyle(nsDependentAtomString(prefix))) {
|
|
| 1192 | + if (containsLinkScriptOrStyle(nsDependentAtomString(prefix))) {
|
|
| 1192 | 1193 | return EmptyString();
|
| 1193 | 1194 | }
|
| 1194 | 1195 | }
|
| 1195 | - if (containsScriptOrStyle(nsDependentAtomString(name->LocalName()))) {
|
|
| 1196 | + if (containsLinkScriptOrStyle(nsDependentAtomString(name->LocalName()))) {
|
|
| 1196 | 1197 | return EmptyString();
|
| 1197 | 1198 | }
|
| 1198 | 1199 | |
| 1199 | 1200 | // Step 2.2. If attribute’s value contains an ASCII case-insensitive match
|
| 1200 | - // for "<script" or "<style", return "Not Nonceable".
|
|
| 1201 | + // for "<link", "<script" or "<style", return "Not Nonceable".
|
|
| 1201 | 1202 | info.mValue->ToString(value);
|
| 1202 | - if (containsScriptOrStyle(value)) {
|
|
| 1203 | + if (containsLinkScriptOrStyle(value)) {
|
|
| 1203 | 1204 | return EmptyString();
|
| 1204 | 1205 | }
|
| 1205 | 1206 | }
|
| ... | ... | @@ -1735,10 +1735,15 @@ bool DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame, |
| 1735 | 1735 | // Transition stub state to megamorphic or generic if warranted.
|
| 1736 | 1736 | MaybeTransition(cx, frame, stub);
|
| 1737 | 1737 | |
| 1738 | + // The array is required to be packed, but may have indexed properties
|
|
| 1739 | + // if its length exceeds MAX_DENSE_ELEMENTS_COUNT. Don't optimize in
|
|
| 1740 | + // that case.
|
|
| 1741 | + bool isIndexed = arr.toObject().as<NativeObject>().isIndexed();
|
|
| 1742 | + |
|
| 1738 | 1743 | // Try attaching a call stub.
|
| 1739 | 1744 | bool handled = false;
|
| 1740 | 1745 | if (op != JSOp::SpreadEval && op != JSOp::StrictSpreadEval &&
|
| 1741 | - stub->state().canAttachStub()) {
|
|
| 1746 | + stub->state().canAttachStub() && !isIndexed) {
|
|
| 1742 | 1747 | // Try CacheIR first:
|
| 1743 | 1748 | Rooted<ArrayObject*> aobj(cx, &arr.toObject().as<ArrayObject>());
|
| 1744 | 1749 | MOZ_ASSERT(IsPackedArray(aobj));
|
| ... | ... | @@ -6431,7 +6431,9 @@ ObjOperandId InlinableNativeIRGenerator::emitLoadArgsArray() { |
| 6431 | 6431 | MOZ_ASSERT(!hasBoundArguments());
|
| 6432 | 6432 | |
| 6433 | 6433 | if (flags_.getArgFormat() == CallFlags::Spread) {
|
| 6434 | - return writer.loadSpreadArgs();
|
|
| 6434 | + ObjOperandId result = writer.loadSpreadArgs();
|
|
| 6435 | + writer.guardArrayIsPacked(result);
|
|
| 6436 | + return result;
|
|
| 6435 | 6437 | }
|
| 6436 | 6438 | |
| 6437 | 6439 | MOZ_ASSERT(flags_.getArgFormat() == CallFlags::FunApplyArray);
|
| ... | ... | @@ -523,7 +523,13 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter { |
| 523 | 523 | ArgumentKind kind = ArgumentKind::Arg0;
|
| 524 | 524 | uint32_t argc = 1;
|
| 525 | 525 | CallFlags flags(CallFlags::Spread);
|
| 526 | - return ObjOperandId(loadArgumentFixedSlot(kind, argc, flags).id());
|
|
| 526 | + ValOperandId argId = loadArgumentFixedSlot(kind, argc, flags);
|
|
| 527 | +#ifdef ENABLE_PORTABLE_BASELINE_INTERP
|
|
| 528 | + // PBL doesn't support implicit unboxing of objects.
|
|
| 529 | + return guardToObject(argId);
|
|
| 530 | +#else
|
|
| 531 | + return ObjOperandId(argId.id());
|
|
| 532 | +#endif
|
|
| 527 | 533 | }
|
| 528 | 534 | |
| 529 | 535 | void callScriptedFunction(ObjOperandId callee, Int32OperandId argc,
|
| ... | ... | @@ -3915,11 +3915,8 @@ uint64_t ICInterpretOps(uint64_t arg0, uint64_t arg1, ICStub* stub, |
| 3915 | 3915 | CACHEOP_CASE(Int32MinMaxArrayResult) {
|
| 3916 | 3916 | ObjOperandId arrayId = cacheIRReader.objOperandId();
|
| 3917 | 3917 | bool isMax = cacheIRReader.readBool();
|
| 3918 | - // ICs that use this opcode depend on implicit unboxing due to
|
|
| 3919 | - // type-overload on ObjOperandId when a value is loaded
|
|
| 3920 | - // directly from an argument slot. We explicitly unbox here.
|
|
| 3921 | 3918 | NativeObject* nobj = reinterpret_cast<NativeObject*>(
|
| 3922 | - &READ_VALUE_REG(arrayId.id()).toObject());
|
|
| 3919 | + READ_REG(arrayId.id()));
|
|
| 3923 | 3920 | uint32_t len = nobj->getDenseInitializedLength();
|
| 3924 | 3921 | if (len == 0) {
|
| 3925 | 3922 | FAIL_IC();
|
| ... | ... | @@ -3948,11 +3945,8 @@ uint64_t ICInterpretOps(uint64_t arg0, uint64_t arg1, ICStub* stub, |
| 3948 | 3945 | CACHEOP_CASE(NumberMinMaxArrayResult) {
|
| 3949 | 3946 | ObjOperandId arrayId = cacheIRReader.objOperandId();
|
| 3950 | 3947 | bool isMax = cacheIRReader.readBool();
|
| 3951 | - // ICs that use this opcode depend on implicit unboxing due to
|
|
| 3952 | - // type-overload on ObjOperandId when a value is loaded
|
|
| 3953 | - // directly from an argument slot. We explicitly unbox here.
|
|
| 3954 | 3948 | NativeObject* nobj = reinterpret_cast<NativeObject*>(
|
| 3955 | - &READ_VALUE_REG(arrayId.id()).toObject());
|
|
| 3949 | + READ_REG(arrayId.id()));
|
|
| 3956 | 3950 | uint32_t len = nobj->getDenseInitializedLength();
|
| 3957 | 3951 | if (len == 0) {
|
| 3958 | 3952 | FAIL_IC();
|
| ... | ... | @@ -27,6 +27,7 @@ |
| 27 | 27 | enctype="multipart/form-data"
|
| 28 | 28 | >
|
| 29 | 29 | <input type="text" name="textInput2" value="value2">
|
| 30 | +<input type="text" name="__proto__" value="regression test for bug 2061470">
|
|
| 30 | 31 | <input type="file" name="testFile">
|
| 31 | 32 | <input type="file" name="emptyFile">
|
| 32 | 33 | </form>
|
| ... | ... | @@ -161,11 +162,19 @@ add_task(async function test_xhr_forms() { |
| 161 | 162 | }
|
| 162 | 163 | let action = new URL(form.action);
|
| 163 | 164 | let formData = new FormData(form);
|
| 164 | - let webRequestFD = {};
|
|
| 165 | 165 | |
| 166 | 166 | let updateActionURL = () => {
|
| 167 | + let webRequestFD = {};
|
|
| 167 | 168 | for (let name of formData.keys()) {
|
| 168 | - webRequestFD[name] = name in uploads ? [uploads[name].fileName] : formData.getAll(name);
|
|
| 169 | + if (Object.hasOwn(webRequestFD, name)) {
|
|
| 170 | + // Ignore duplicate keys; formData.getAll already read all values.
|
|
| 171 | + continue;
|
|
| 172 | + }
|
|
| 173 | + const value = Object.hasOwn(uploads, name) ? [uploads[name].fileName] : formData.getAll(name);
|
|
| 174 | + // Cannot use webRequestFD[name] = value, because for "__proto__" as
|
|
| 175 | + // name, that would trigger the Object.prototype.__proto__ setter
|
|
| 176 | + // instead of defining a data property.
|
|
| 177 | + Object.defineProperty(webRequestFD, name, { value, enumerable: true });
|
|
| 169 | 178 | }
|
| 170 | 179 | action.searchParams.set("upload", JSON.stringify(webRequestFD));
|
| 171 | 180 | action.searchParams.set("enctype", form.enctype);
|
| ... | ... | @@ -117,22 +117,6 @@ class Headers extends Map { |
| 117 | 117 | }
|
| 118 | 118 | }
|
| 119 | 119 | |
| 120 | -/**
|
|
| 121 | - * Creates a new Object with a corresponding property for every
|
|
| 122 | - * key-value pair in the given Map.
|
|
| 123 | - *
|
|
| 124 | - * @param {Map} map
|
|
| 125 | - * The map to convert.
|
|
| 126 | - * @returns {object}
|
|
| 127 | - */
|
|
| 128 | -function mapToObject(map) {
|
|
| 129 | - let result = {};
|
|
| 130 | - for (let [key, value] of map) {
|
|
| 131 | - result[key] = value;
|
|
| 132 | - }
|
|
| 133 | - return result;
|
|
| 134 | -}
|
|
| 135 | - |
|
| 136 | 120 | /**
|
| 137 | 121 | * Rewinds the given seekable input stream to its beginning, and catches
|
| 138 | 122 | * any resulting errors.
|
| ... | ... | @@ -446,7 +430,7 @@ function createFormData(stream, channel, lenient) { |
| 446 | 430 | try {
|
| 447 | 431 | let formData = parseFormData(stream, channel, lenient);
|
| 448 | 432 | if (formData) {
|
| 449 | - return mapToObject(formData);
|
|
| 433 | + return Object.fromEntries(formData);
|
|
| 450 | 434 | }
|
| 451 | 435 | } catch (e) {
|
| 452 | 436 | Cu.reportError(e);
|