[tor-commits] [Git][tpo/applications/mullvad-browser][mullvad-browser-115.16.0esr-13.5-1] 7 commits: Bug 1881037 - Part 1: Stop showing unknown protocol error pages for...

ma1 (@ma1) git at gitlab.torproject.org
Mon Sep 30 22:58:35 UTC 2024



ma1 pushed to branch mullvad-browser-115.16.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser


Commits:
eafe617f by Nika Layzell at 2024-10-01T00:57:18+02:00
Bug 1881037 - Part 1: Stop showing unknown protocol error pages for web-triggered loads, r=smaug,necko-reviewers,kershaw, a=dsmith

Differential Revision: https://phabricator.services.mozilla.com/D217495

- - - - -
db726edf by Paul Zuehlcke at 2024-10-01T00:57:20+02:00
Bug 1916659,  a=diannaS

Original Revision: https://phabricator.services.mozilla.com/D222629

Differential Revision: https://phabricator.services.mozilla.com/D222934

- - - - -
be142b0d by André Bargull at 2024-10-01T00:57:21+02:00
Bug 1915249: Add more nodiscard.  a=RyanVM

Original Revision: https://phabricator.services.mozilla.com/D220311

Differential Revision: https://phabricator.services.mozilla.com/D221663
- - - - -
bfc54ed4 by Emilio Cobos Álvarez at 2024-10-01T00:57:23+02:00
Bug 1914106 - Deal with insertRule edge-case. r=jwatt a=RyanVM

When there's trailing garbage after an @import rule we throw, but we
still trigger the load (that's not great but not trivial to change).

Deal with that case before calling ImportRuleLoaded().

Differential Revision: https://phabricator.services.mozilla.com/D219783
- - - - -
cb01df5c by Steve Fink at 2024-10-01T00:57:25+02:00
Bug 1912471 - Disallow deserializing structured clone buffers with transferables more than once r=iain, a=dsmith

Differential Revision: https://phabricator.services.mozilla.com/D220644
- - - - -
84dc8a8a by Nika Layzell at 2024-10-01T00:57:26+02:00
Bug 1911745 - Unify BrowsingContext flag coherency checks, r=mccr8

Previously these checks were largely diagnostic tools for finding bugs
in other code as it evolves. This unifies the checks a bit more and
makes them stronger for BrowsingContexts created over IPC, providing a
place for more coherency checks to be added in the future.

Differential Revision: https://phabricator.services.mozilla.com/D218860

- - - - -
0fe417ba by Kershaw Chang at 2024-10-01T00:57:28+02:00
Bug 1907726 - Make sure WebTransportSessionProxy::NotifyDatagramReceived is called after OnStopRequest,  a=RyanVM

The crash occurs because WebTransportSessionProxy::OnDatagramReceivedInternal is called before WebTransportSessionProxy::OnStopRequest.
When this happens, WebTransportSessionProxy::mTarget is the main thread, so a task is dispatched to the main thread. This causes WebTransportSessionProxy::NotifyDatagramReceived to be called on the main thread.

If WebTransportSessionProxy::NotifyDatagramReceived is invoked while WebTransportSessionProxy::mStopRequestCalled is true, it can lead to OnDatagramReceived being called on the main thread (instead of the socket thread), resulting in a crash.

Original Revision: https://phabricator.services.mozilla.com/D220013

Differential Revision: https://phabricator.services.mozilla.com/D221661
- - - - -


22 changed files:

- browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js
- browser/components/prompts/PromptCollection.sys.mjs
- docshell/base/BrowsingContext.cpp
- docshell/base/BrowsingContext.h
- docshell/base/nsDocShell.cpp
- docshell/base/nsDocShell.h
- dom/base/Document.cpp
- dom/base/Document.h
- dom/base/ShadowRoot.cpp
- dom/base/ShadowRoot.h
- dom/filesystem/tests/script_promptHandler.js
- js/public/StructuredClone.h
- js/public/friend/ErrorNumbers.msg
- js/src/jit-test/tests/structured-clone/transferable-cleanup.js
- js/src/jit/IonAnalysis.cpp
- js/src/vm/StructuredClone.cpp
- layout/style/ServoStyleSet.cpp
- layout/style/ServoStyleSet.h
- layout/style/StyleSheet.cpp
- netwerk/ipc/DocumentLoadListener.cpp
- netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
- + testing/web-platform/tests/css/cssom/insertRule-import-trailing-garbage-crash.html


Changes:

=====================================
browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js
=====================================
@@ -101,8 +101,29 @@ async function testUploadPrompt(confirmUpload) {
     // Wait for confirmation prompt
     let prompt = await promptPromise;
     ok(prompt, "Shown upload confirmation prompt");
+
     is(prompt.ui.button0.label, "Upload", "Accept button label");
+    ok(
+      prompt.ui.button0.disabled,
+      "Accept button should be disabled by the security delay initially."
+    );
+
     ok(prompt.ui.button1.hasAttribute("default"), "Cancel is default button");
+    ok(
+      !prompt.ui.button1.disabled,
+      "Cancel button should not be disabled by the security delay."
+    );
+
+    info("Wait for the security delay to pass.");
+    let delayTime = Services.prefs.getIntPref("security.dialog_enable_delay");
+    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+    await new Promise(resolve => setTimeout(resolve, delayTime + 100));
+
+    ok(
+      !prompt.ui.button0.disabled,
+      "Accept button should no longer be disabled."
+    );
+    ok(!prompt.ui.button1.disabled, "Cancel button should remain enabled.");
 
     // Close confirmation prompt
     await PromptTestUtils.handlePrompt(prompt, {


=====================================
browser/components/prompts/PromptCollection.sys.mjs
=====================================
@@ -156,7 +156,7 @@ export class PromptCollection {
         Services.prompt.MODAL_TYPE_TAB,
         title,
         message,
-        buttonFlags,
+        buttonFlags | Ci.nsIPrompt.BUTTON_DELAY_ENABLE,
         acceptLabel,
         null,
         null,


=====================================
docshell/base/BrowsingContext.cpp
=====================================
@@ -572,9 +572,19 @@ mozilla::ipc::IPCResult BrowsingContext::CreateFromIPC(
   context->mRequestContextId = aInit.mRequestContextId;
   // NOTE: Private browsing ID is set by `SetOriginAttributes`.
 
+  if (const char* failure =
+          context->BrowsingContextCoherencyChecks(aOriginProcess)) {
+    mozilla::ipc::IProtocol* actor = aOriginProcess;
+    if (!actor) {
+      actor = ContentChild::GetSingleton();
+    }
+    return IPC_FAIL(actor, "Incoherent BrowsingContext");
+  }
+
   Register(context);
 
-  return context->Attach(/* aFromIPC */ true, aOriginProcess);
+  context->Attach(/* aFromIPC */ true, aOriginProcess);
+  return IPC_OK();
 }
 
 BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
@@ -786,8 +796,64 @@ void BrowsingContext::Embed() {
   }
 }
 
-mozilla::ipc::IPCResult BrowsingContext::Attach(bool aFromIPC,
-                                                ContentParent* aOriginProcess) {
+const char* BrowsingContext::BrowsingContextCoherencyChecks(
+    ContentParent* aOriginProcess) {
+#define COHERENCY_ASSERT(condition) \
+  if (!(condition)) return "Assertion " #condition " failed";
+
+  if (mGroup->IsPotentiallyCrossOriginIsolated() !=
+      (Top()->GetOpenerPolicy() ==
+       nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP)) {
+    return "Invalid CrossOriginIsolated state";
+  }
+
+  if (aOriginProcess && !IsContent()) {
+    return "Content cannot create chrome BCs";
+  }
+
+  // LoadContext should generally match our opener or parent.
+  if (IsContent()) {
+    if (RefPtr<BrowsingContext> opener = GetOpener()) {
+      COHERENCY_ASSERT(opener->mType == mType);
+      COHERENCY_ASSERT(opener->mGroup == mGroup);
+      COHERENCY_ASSERT(opener->mUseRemoteTabs == mUseRemoteTabs);
+      COHERENCY_ASSERT(opener->mUseRemoteSubframes == mUseRemoteSubframes);
+      COHERENCY_ASSERT(opener->mPrivateBrowsingId == mPrivateBrowsingId);
+      COHERENCY_ASSERT(
+          opener->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
+    }
+  }
+  if (RefPtr<BrowsingContext> parent = GetParent()) {
+    COHERENCY_ASSERT(parent->mType == mType);
+    COHERENCY_ASSERT(parent->mGroup == mGroup);
+    COHERENCY_ASSERT(parent->mUseRemoteTabs == mUseRemoteTabs);
+    COHERENCY_ASSERT(parent->mUseRemoteSubframes == mUseRemoteSubframes);
+    COHERENCY_ASSERT(parent->mPrivateBrowsingId == mPrivateBrowsingId);
+    COHERENCY_ASSERT(
+        parent->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
+  }
+
+  // UseRemoteSubframes and UseRemoteTabs must match.
+  if (mUseRemoteSubframes && !mUseRemoteTabs) {
+    return "Cannot set useRemoteSubframes without also setting useRemoteTabs";
+  }
+
+  // Double-check OriginAttributes/Private Browsing
+  // Chrome browsing contexts must not have a private browsing OriginAttribute
+  // Content browsing contexts must maintain the equality:
+  // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
+  if (IsChrome()) {
+    COHERENCY_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
+  } else {
+    COHERENCY_ASSERT(mOriginAttributes.mPrivateBrowsingId ==
+                     mPrivateBrowsingId);
+  }
+#undef COHERENCY_ASSERT
+
+  return nullptr;
+}
+
+void BrowsingContext::Attach(bool aFromIPC, ContentParent* aOriginProcess) {
   MOZ_DIAGNOSTIC_ASSERT(!mEverAttached);
   MOZ_DIAGNOSTIC_ASSERT_IF(aFromIPC, aOriginProcess || XRE_IsContentProcess());
   mEverAttached = true;
@@ -806,25 +872,15 @@ mozilla::ipc::IPCResult BrowsingContext::Attach(bool aFromIPC,
   MOZ_DIAGNOSTIC_ASSERT(mGroup);
   MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded);
 
-  if (mGroup->IsPotentiallyCrossOriginIsolated() !=
-      (Top()->GetOpenerPolicy() ==
-       nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP)) {
-    MOZ_DIAGNOSTIC_ASSERT(aFromIPC);
-    if (aFromIPC) {
-      auto* actor = aOriginProcess
-                        ? static_cast<mozilla::ipc::IProtocol*>(aOriginProcess)
-                        : static_cast<mozilla::ipc::IProtocol*>(
-                              ContentChild::GetSingleton());
-      return IPC_FAIL(
-          actor,
-          "Invalid CrossOriginIsolated state in BrowsingContext::Attach call");
-    } else {
-      MOZ_CRASH(
-          "Invalid CrossOriginIsolated state in BrowsingContext::Attach call");
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+  // We'll already have checked this if `aFromIPC` is set before calling this
+  // function.
+  if (!aFromIPC) {
+    if (const char* failure = BrowsingContextCoherencyChecks(aOriginProcess)) {
+      MOZ_CRASH_UNSAFE_PRINTF("Incoherent BrowsingContext: %s", failure);
     }
   }
-
-  AssertCoherentLoadContext();
+#endif
 
   // Add ourselves either to our parent or BrowsingContextGroup's child list.
   // Important: We shouldn't return IPC_FAIL after this point, since the
@@ -906,7 +962,6 @@ mozilla::ipc::IPCResult BrowsingContext::Attach(bool aFromIPC,
   if (XRE_IsParentProcess()) {
     Canonical()->CanonicalAttach();
   }
-  return IPC_OK();
 }
 
 void BrowsingContext::Detach(bool aFromIPC) {
@@ -1743,40 +1798,6 @@ nsresult BrowsingContext::SetOriginAttributes(const OriginAttributes& aAttrs) {
   return NS_OK;
 }
 
-void BrowsingContext::AssertCoherentLoadContext() {
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-  // LoadContext should generally match our opener or parent.
-  if (IsContent()) {
-    if (RefPtr<BrowsingContext> opener = GetOpener()) {
-      MOZ_DIAGNOSTIC_ASSERT(opener->mType == mType);
-      MOZ_DIAGNOSTIC_ASSERT(opener->mGroup == mGroup);
-      MOZ_DIAGNOSTIC_ASSERT(opener->mUseRemoteTabs == mUseRemoteTabs);
-      MOZ_DIAGNOSTIC_ASSERT(opener->mUseRemoteSubframes == mUseRemoteSubframes);
-      MOZ_DIAGNOSTIC_ASSERT(opener->mPrivateBrowsingId == mPrivateBrowsingId);
-      MOZ_DIAGNOSTIC_ASSERT(
-          opener->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
-    }
-  }
-  if (RefPtr<BrowsingContext> parent = GetParent()) {
-    MOZ_DIAGNOSTIC_ASSERT(parent->mType == mType);
-    MOZ_DIAGNOSTIC_ASSERT(parent->mGroup == mGroup);
-    MOZ_DIAGNOSTIC_ASSERT(parent->mUseRemoteTabs == mUseRemoteTabs);
-    MOZ_DIAGNOSTIC_ASSERT(parent->mUseRemoteSubframes == mUseRemoteSubframes);
-    MOZ_DIAGNOSTIC_ASSERT(parent->mPrivateBrowsingId == mPrivateBrowsingId);
-    MOZ_DIAGNOSTIC_ASSERT(
-        parent->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
-  }
-
-  // UseRemoteSubframes and UseRemoteTabs must match.
-  MOZ_DIAGNOSTIC_ASSERT(
-      !mUseRemoteSubframes || mUseRemoteTabs,
-      "Cannot set useRemoteSubframes without also setting useRemoteTabs");
-
-  // Double-check OriginAttributes/Private Browsing
-  AssertOriginAttributesMatchPrivateBrowsing();
-#endif
-}
-
 void BrowsingContext::AssertOriginAttributesMatchPrivateBrowsing() {
   // Chrome browsing contexts must not have a private browsing OriginAttribute
   // Content browsing contexts must maintain the equality:


=====================================
docshell/base/BrowsingContext.h
=====================================
@@ -971,7 +971,18 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
                                        bool aHasPostData);
 
  private:
-  mozilla::ipc::IPCResult Attach(bool aFromIPC, ContentParent* aOriginProcess);
+  // Assert that this BrowsingContext is coherent relative to related
+  // BrowsingContexts. This will be run before the BrowsingContext is attached.
+  //
+  // A non-null string return value indicates that there was a coherency check
+  // failure, which will be handled with either a crash or IPC failure.
+  //
+  // If provided, `aOriginProcess` is the process which is responsible for the
+  // creation of this BrowsingContext.
+  [[nodiscard]] const char* BrowsingContextCoherencyChecks(
+      ContentParent* aOriginProcess);
+
+  void Attach(bool aFromIPC, ContentParent* aOriginProcess);
 
   // Recomputes whether we can execute scripts in this BrowsingContext based on
   // the value of AllowJavascript() and whether scripts are allowed in the
@@ -985,10 +996,6 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
 
   void AssertOriginAttributesMatchPrivateBrowsing();
 
-  // Assert that the BrowsingContext's LoadContext flags appear coherent
-  // relative to related BrowsingContexts.
-  void AssertCoherentLoadContext();
-
   friend class ::nsOuterWindowProxy;
   friend class ::nsGlobalWindowOuter;
   friend class WindowContext;


=====================================
docshell/base/nsDocShell.cpp
=====================================
@@ -6254,7 +6254,7 @@ already_AddRefed<nsIURI> nsDocShell::AttemptURIFixup(
 
 nsresult nsDocShell::FilterStatusForErrorPage(
     nsresult aStatus, nsIChannel* aChannel, uint32_t aLoadType,
-    bool aIsTopFrame, bool aUseErrorPages, bool aIsInitialDocument,
+    bool aIsTopFrame, bool aUseErrorPages,
     bool* aSkippedUnknownProtocolNavigation) {
   // Errors to be shown only on top-level frames
   if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
@@ -6298,18 +6298,10 @@ nsresult nsDocShell::FilterStatusForErrorPage(
 
   if (aStatus == NS_ERROR_UNKNOWN_PROTOCOL) {
     // For unknown protocols we only display an error if the load is triggered
-    // by the browser itself, or we're replacing the initial document (and
-    // nothing else). Showing the error for page-triggered navigations causes
-    // annoying behavior for users, see bug 1528305.
-    //
-    // We could, maybe, try to detect if this is in response to some user
-    // interaction (like clicking a link, or something else) and maybe show
-    // the error page in that case. But this allows for ctrl+clicking and such
-    // to see the error page.
+    // by the browser itself. Showing the error for page-triggered navigations
+    // causes annoying behavior for users, see bug 1528305.
     nsCOMPtr<nsILoadInfo> info = aChannel->LoadInfo();
-    if (!info->TriggeringPrincipal()->IsSystemPrincipal() &&
-        StaticPrefs::dom_no_unknown_protocol_error_enabled() &&
-        !aIsInitialDocument) {
+    if (!info->TriggeringPrincipal()->IsSystemPrincipal()) {
       if (aSkippedUnknownProtocolNavigation) {
         *aSkippedUnknownProtocolNavigation = true;
       }
@@ -6459,12 +6451,9 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
                                 aStatus == NS_ERROR_CONTENT_BLOCKED);
     UnblockEmbedderLoadEventForFailure(fireFrameErrorEvent);
 
-    bool isInitialDocument =
-        !GetExtantDocument() || GetExtantDocument()->IsInitialDocument();
     bool skippedUnknownProtocolNavigation = false;
     aStatus = FilterStatusForErrorPage(aStatus, aChannel, mLoadType, isTopFrame,
                                        mBrowsingContext->GetUseErrorPages(),
-                                       isInitialDocument,
                                        &skippedUnknownProtocolNavigation);
     hadErrorStatus = true;
     if (NS_FAILED(aStatus)) {


=====================================
docshell/base/nsDocShell.h
=====================================
@@ -464,7 +464,7 @@ class nsDocShell final : public nsDocLoader,
   // navigation.
   static nsresult FilterStatusForErrorPage(
       nsresult aStatus, nsIChannel* aChannel, uint32_t aLoadType,
-      bool aIsTopFrame, bool aUseErrorPages, bool aIsInitialDocument,
+      bool aIsTopFrame, bool aUseErrorPages,
       bool* aSkippedUnknownProtocolNavigation = nullptr);
 
   // Notify consumers of a search being loaded through the observer service:


=====================================
dom/base/Document.cpp
=====================================
@@ -8266,7 +8266,7 @@ void Document::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
   }
 }
 
-void Document::ImportRuleLoaded(dom::CSSImportRule& aRule, StyleSheet& aSheet) {
+void Document::ImportRuleLoaded(StyleSheet& aSheet) {
   if (aSheet.IsApplicable()) {
     ApplicableStylesChanged();
   }


=====================================
dom/base/Document.h
=====================================
@@ -2135,7 +2135,7 @@ class Document : public nsINode,
   void RuleAdded(StyleSheet&, css::Rule&);
   void RuleRemoved(StyleSheet&, css::Rule&);
   void SheetCloned(StyleSheet&) {}
-  void ImportRuleLoaded(CSSImportRule&, StyleSheet&);
+  void ImportRuleLoaded(StyleSheet&);
 
   /**
    * Flush notifications for this document and its parent documents


=====================================
dom/base/ShadowRoot.cpp
=====================================
@@ -412,7 +412,7 @@ void ShadowRoot::RuleChanged(StyleSheet& aSheet, css::Rule*,
   ApplicableRulesChanged();
 }
 
-void ShadowRoot::ImportRuleLoaded(CSSImportRule&, StyleSheet& aSheet) {
+void ShadowRoot::ImportRuleLoaded(StyleSheet& aSheet) {
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(aSheet);
   }


=====================================
dom/base/ShadowRoot.h
=====================================
@@ -86,7 +86,7 @@ class ShadowRoot final : public DocumentFragment,
   void RuleAdded(StyleSheet&, css::Rule&);
   void RuleRemoved(StyleSheet&, css::Rule&);
   void RuleChanged(StyleSheet&, css::Rule*, StyleRuleChangeKind);
-  void ImportRuleLoaded(CSSImportRule&, StyleSheet&);
+  void ImportRuleLoaded(StyleSheet&);
   void SheetCloned(StyleSheet&);
   void StyleSheetApplicableStateChanged(StyleSheet&);
 


=====================================
dom/filesystem/tests/script_promptHandler.js
=====================================
@@ -2,7 +2,45 @@
 
 let dialogObserverTopic = "common-dialog-loaded";
 
-function dialogObserver(subj, topic, data) {
+function waitForButtonEnabledState(button) {
+  return new Promise(resolve => {
+    // Check if the button is already enabled (not disabled)
+    if (!button.disabled) {
+      resolve();
+      return;
+    }
+
+    // Create a MutationObserver instance
+    let win = button.ownerGlobal;
+    let { MutationObserver } = win;
+    const observer = new MutationObserver(mutationsList => {
+      for (const mutation of mutationsList) {
+        if (
+          mutation.type === "attributes" &&
+          mutation.attributeName === "disabled"
+        ) {
+          if (!button.disabled) {
+            // Resolve the promise when the button is enabled
+            observer.disconnect(); // Stop observing
+            resolve();
+          }
+        }
+      }
+    });
+
+    // Start observing the button for changes to the 'disabled' attribute
+    observer.observe(button, {
+      attributes: true,
+      attributeFilter: ["disabled"],
+    });
+  });
+}
+
+async function dialogObserver(subj) {
+  let dialog = subj.document.querySelector("dialog");
+  let acceptButton = dialog.getButton("accept");
+  await waitForButtonEnabledState(acceptButton);
+
   subj.document.querySelector("dialog").acceptDialog();
   sendAsyncMessage("promptAccepted");
 }


=====================================
js/public/StructuredClone.h
=====================================
@@ -744,6 +744,7 @@ class JS_PUBLIC_API JSAutoStructuredCloneBuffer {
 #define JS_SCERR_WASM_NO_TRANSFER 6
 #define JS_SCERR_NOT_CLONABLE 7
 #define JS_SCERR_NOT_CLONABLE_WITH_COOP_COEP 8
+#define JS_SCERR_TRANSFERABLE_TWICE 9
 
 JS_PUBLIC_API bool JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1,
                                      uint32_t* p2);


=====================================
js/public/friend/ErrorNumbers.msg
=====================================
@@ -527,6 +527,7 @@ MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION,    0, JSEXN_ERR, "unsupported structured clo
 MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA,  1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
 MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE,     0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
 MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE,     0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
+MSG_DEF(JSMSG_SC_TRANSFERABLE_TWICE,   0, JSEXN_TYPEERR, "structured clone cannot transfer twice")
 MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE,     0, JSEXN_TYPEERR, "unsupported type for structured data")
 MSG_DEF(JSMSG_SC_NOT_CLONABLE,         1, JSEXN_TYPEERR, "The {0} object cannot be serialized. The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers will enable this in the future.")
 MSG_DEF(JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP, 1, JSEXN_TYPEERR, "The {0} object cannot be serialized. The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers can be used to enable this.")


=====================================
js/src/jit-test/tests/structured-clone/transferable-cleanup.js
=====================================
@@ -160,6 +160,15 @@ function testMultiWithDeserializeReadTransferErrorHelper(g, BASE, desc) {
     } catch (e) {
         assertEq(e.message.includes("invalid transferable"), true);
     }
+
+    try {
+        // This fails without logging anything, since the re-transfer will be caught
+        // by looking at its header before calling any callbacks.
+        let clone = deserialize(s);
+    } catch (e) {
+        assertEq(e.message.includes("cannot transfer twice"), true);
+    }
+
     s = null;
     gc();
     printTrace(arguments.callee.name, g, BASE, obj.log, "deserialize");
@@ -170,6 +179,7 @@ function testMultiWithDeserializeReadTransferErrorHelper(g, BASE, desc) {
         // which comes before the main reading. obj transfer data is now owned by its
         // clone. obj3 transfer data was not successfully handed over to a new object,
         // so it is still owned by the clone buffer and must be discarded with freeTransfer.
+        // 'F' means the data is freed.
         BASE + 3, "F",
     ], "deserialize " + desc);
     obj.log = null;


=====================================
js/src/jit/IonAnalysis.cpp
=====================================
@@ -29,8 +29,9 @@ using MPhiUseIteratorStack =
 
 // Look for Phi uses with a depth-first search. If any uses are found the stack
 // of MPhi instructions is returned in the |worklist| argument.
-static bool DepthFirstSearchUse(MIRGenerator* mir,
-                                MPhiUseIteratorStack& worklist, MPhi* phi) {
+[[nodiscard]] static bool DepthFirstSearchUse(MIRGenerator* mir,
+                                              MPhiUseIteratorStack& worklist,
+                                              MPhi* phi) {
   // Push a Phi and the next use to iterate over in the worklist.
   auto push = [&worklist](MPhi* phi, MUseIterator use) -> bool {
     phi->setInWorklist();
@@ -131,9 +132,9 @@ static bool DepthFirstSearchUse(MIRGenerator* mir,
   return true;
 }
 
-static bool FlagPhiInputsAsImplicitlyUsed(MIRGenerator* mir, MBasicBlock* block,
-                                          MBasicBlock* succ,
-                                          MPhiUseIteratorStack& worklist) {
+[[nodiscard]] static bool FlagPhiInputsAsImplicitlyUsed(
+    MIRGenerator* mir, MBasicBlock* block, MBasicBlock* succ,
+    MPhiUseIteratorStack& worklist) {
   // When removing an edge between 2 blocks, we might remove the ability of
   // later phases to figure out that the uses of a Phi should be considered as
   // a use of all its inputs. Thus we need to mark the Phi inputs as being
@@ -265,7 +266,7 @@ static MInstructionIterator FindFirstInstructionAfterBail(MBasicBlock* block) {
 
 // Given an iterator pointing to the first removed instruction, mark
 // the operands of each removed instruction as having implicit uses.
-static bool FlagOperandsAsImplicitlyUsedAfter(
+[[nodiscard]] static bool FlagOperandsAsImplicitlyUsedAfter(
     MIRGenerator* mir, MBasicBlock* block, MInstructionIterator firstRemoved) {
   MOZ_ASSERT(firstRemoved->block() == block);
 
@@ -312,8 +313,8 @@ static bool FlagOperandsAsImplicitlyUsedAfter(
   return true;
 }
 
-static bool FlagEntryResumePointOperands(MIRGenerator* mir,
-                                         MBasicBlock* block) {
+[[nodiscard]] static bool FlagEntryResumePointOperands(MIRGenerator* mir,
+                                                       MBasicBlock* block) {
   // Flag observable operands of the entry resume point as having implicit uses.
   MResumePoint* rp = block->entryResumePoint();
   while (rp) {
@@ -334,8 +335,8 @@ static bool FlagEntryResumePointOperands(MIRGenerator* mir,
   return true;
 }
 
-static bool FlagAllOperandsAsImplicitlyUsed(MIRGenerator* mir,
-                                            MBasicBlock* block) {
+[[nodiscard]] static bool FlagAllOperandsAsImplicitlyUsed(MIRGenerator* mir,
+                                                          MBasicBlock* block) {
   return FlagEntryResumePointOperands(mir, block) &&
          FlagOperandsAsImplicitlyUsedAfter(mir, block, block->begin());
 }
@@ -420,12 +421,16 @@ bool jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph) {
     if (!block->isMarked()) {
       // If we are removing the block entirely, mark the operands of every
       // instruction as being implicitly used.
-      FlagAllOperandsAsImplicitlyUsed(mir, block);
+      if (!FlagAllOperandsAsImplicitlyUsed(mir, block)) {
+        return false;
+      }
     } else if (block->alwaysBails()) {
       // If we are only trimming instructions after a bail, only mark operands
       // of removed instructions.
       MInstructionIterator firstRemoved = FindFirstInstructionAfterBail(block);
-      FlagOperandsAsImplicitlyUsedAfter(mir, block, firstRemoved);
+      if (!FlagOperandsAsImplicitlyUsedAfter(mir, block, firstRemoved)) {
+        return false;
+      }
     }
   }
 
@@ -503,7 +508,8 @@ bool jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph) {
   return true;
 }
 
-static bool SplitCriticalEdgesForBlock(MIRGraph& graph, MBasicBlock* block) {
+[[nodiscard]] static bool SplitCriticalEdgesForBlock(MIRGraph& graph,
+                                                     MBasicBlock* block) {
   if (block->numSuccessors() < 2) {
     return true;
   }
@@ -767,8 +773,8 @@ static bool IsDiamondPattern(MBasicBlock* initialBlock) {
   return true;
 }
 
-static bool MaybeFoldDiamondConditionBlock(MIRGraph& graph,
-                                           MBasicBlock* initialBlock) {
+[[nodiscard]] static bool MaybeFoldDiamondConditionBlock(
+    MIRGraph& graph, MBasicBlock* initialBlock) {
   MOZ_ASSERT(IsDiamondPattern(initialBlock));
 
   // Optimize the MIR graph to improve the code generated for conditional
@@ -936,8 +942,8 @@ static bool IsTrianglePattern(MBasicBlock* initialBlock) {
   return false;
 }
 
-static bool MaybeFoldTriangleConditionBlock(MIRGraph& graph,
-                                            MBasicBlock* initialBlock) {
+[[nodiscard]] static bool MaybeFoldTriangleConditionBlock(
+    MIRGraph& graph, MBasicBlock* initialBlock) {
   MOZ_ASSERT(IsTrianglePattern(initialBlock));
 
   // Optimize the MIR graph to improve the code generated for boolean
@@ -1089,8 +1095,8 @@ static bool MaybeFoldTriangleConditionBlock(MIRGraph& graph,
   return true;
 }
 
-static bool MaybeFoldConditionBlock(MIRGraph& graph,
-                                    MBasicBlock* initialBlock) {
+[[nodiscard]] static bool MaybeFoldConditionBlock(MIRGraph& graph,
+                                                  MBasicBlock* initialBlock) {
   if (IsDiamondPattern(initialBlock)) {
     return MaybeFoldDiamondConditionBlock(graph, initialBlock);
   }
@@ -1100,7 +1106,8 @@ static bool MaybeFoldConditionBlock(MIRGraph& graph,
   return true;
 }
 
-static bool MaybeFoldTestBlock(MIRGraph& graph, MBasicBlock* initialBlock) {
+[[nodiscard]] static bool MaybeFoldTestBlock(MIRGraph& graph,
+                                             MBasicBlock* initialBlock) {
   // Handle test expressions on more than two inputs. For example
   // |if ((x > 10) && (y > 20) && (z > 30)) { ... }|, which results in the below
   // pattern.
@@ -2752,7 +2759,9 @@ bool jit::RemoveUnmarkedBlocks(MIRGenerator* mir, MIRGraph& graph,
         continue;
       }
 
-      FlagAllOperandsAsImplicitlyUsed(mir, block);
+      if (!FlagAllOperandsAsImplicitlyUsed(mir, block)) {
+        return false;
+      }
     }
 
     // Find unmarked blocks and remove them.
@@ -4003,8 +4012,8 @@ bool jit::EliminateRedundantShapeGuards(MIRGraph& graph) {
   return true;
 }
 
-static bool TryEliminateGCBarriersForAllocation(TempAllocator& alloc,
-                                                MInstruction* allocation) {
+[[nodiscard]] static bool TryEliminateGCBarriersForAllocation(
+    TempAllocator& alloc, MInstruction* allocation) {
   MOZ_ASSERT(allocation->type() == MIRType::Object);
 
   JitSpew(JitSpew_RedundantGCBarriers, "Analyzing allocation %s",


=====================================
js/src/vm/StructuredClone.cpp
=====================================
@@ -172,17 +172,25 @@ enum StructuredDataType : uint32_t {
 
 /*
  * Format of transfer map:
- *   <SCTAG_TRANSFER_MAP_HEADER, TransferableMapHeader(UNREAD|TRANSFERRED)>
- *   numTransferables (64 bits)
- *   array of:
- *     <SCTAG_TRANSFER_MAP_*, TransferableOwnership>
- *     pointer (64 bits)
- *     extraData (64 bits), eg byte length for ArrayBuffers
+ *   - <SCTAG_TRANSFER_MAP_HEADER, UNREAD|TRANSFERRING|TRANSFERRED>
+ *   - numTransferables (64 bits)
+ *   - array of:
+ *     - <SCTAG_TRANSFER_MAP_*, TransferableOwnership> pointer (64
+ *       bits)
+ *     - extraData (64 bits), eg byte length for ArrayBuffers
+ *     - any data written for custom transferables
  */
 
 // Data associated with an SCTAG_TRANSFER_MAP_HEADER that tells whether the
-// contents have been read out yet or not.
-enum TransferableMapHeader { SCTAG_TM_UNREAD = 0, SCTAG_TM_TRANSFERRED };
+// contents have been read out yet or not. TRANSFERRING is for the case where we
+// have started but not completed reading, which due to errors could mean that
+// there are things still owned by the clone buffer that need to be released, so
+// discarding should not just be skipped.
+enum TransferableMapHeader {
+  SCTAG_TM_UNREAD = 0,
+  SCTAG_TM_TRANSFERRING,
+  SCTAG_TM_TRANSFERRED
+};
 
 static inline uint64_t PairToUInt64(uint32_t tag, uint32_t data) {
   return uint64_t(data) | (uint64_t(tag) << 32);
@@ -693,6 +701,10 @@ static void ReportDataCloneError(JSContext* cx,
       errorNumber = JSMSG_SC_SHMEM_TRANSFERABLE;
       break;
 
+    case JS_SCERR_TRANSFERABLE_TWICE:
+      errorNumber = JSMSG_SC_TRANSFERABLE_TWICE;
+      break;
+
     case JS_SCERR_TYPED_ARRAY_DETACHED:
       errorNumber = JSMSG_TYPED_ARRAY_DETACHED;
       break;
@@ -3209,11 +3221,21 @@ bool JSStructuredCloneReader::readTransferMap() {
     return in.reportTruncated();
   }
 
+  auto transferState = static_cast<TransferableMapHeader>(data);
+
   if (tag != SCTAG_TRANSFER_MAP_HEADER ||
-      TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED) {
+      transferState == SCTAG_TM_TRANSFERRED) {
     return true;
   }
 
+  if (transferState == SCTAG_TM_TRANSFERRING) {
+    ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE_TWICE, closure);
+    return false;
+  }
+
+  headerPos.write(
+      PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRING));
+
   uint64_t numTransferables;
   MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
   if (!in.read(&numTransferables)) {
@@ -3329,7 +3351,7 @@ bool JSStructuredCloneReader::readTransferMap() {
 #ifdef DEBUG
   SCInput::getPair(headerPos.peek(), &tag, &data);
   MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_HEADER);
-  MOZ_ASSERT(TransferableMapHeader(data) != SCTAG_TM_TRANSFERRED);
+  MOZ_ASSERT(TransferableMapHeader(data) == SCTAG_TM_TRANSFERRING);
 #endif
   headerPos.write(
       PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED));


=====================================
layout/style/ServoStyleSet.cpp
=====================================
@@ -954,7 +954,7 @@ static OriginFlags ToOriginFlags(StyleOrigin aOrigin) {
   }
 }
 
-void ServoStyleSet::ImportRuleLoaded(dom::CSSImportRule&, StyleSheet& aSheet) {
+void ServoStyleSet::ImportRuleLoaded(StyleSheet& aSheet) {
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(aSheet);
   }


=====================================
layout/style/ServoStyleSet.h
=====================================
@@ -133,7 +133,7 @@ class ServoStyleSet {
   void RuleRemoved(StyleSheet&, css::Rule&);
   void RuleChanged(StyleSheet&, css::Rule*, StyleRuleChangeKind);
   void SheetCloned(StyleSheet&);
-  void ImportRuleLoaded(dom::CSSImportRule&, StyleSheet&);
+  void ImportRuleLoaded(StyleSheet&);
 
   // Runs style invalidation due to document state changes.
   void InvalidateStyleForDocumentStateChanges(


=====================================
layout/style/StyleSheet.cpp
=====================================
@@ -836,15 +836,19 @@ StyleSheet::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
   if (!aSheet->GetParentSheet()) {
     return NS_OK;  // ignore if sheet has been detached already
   }
-  MOZ_ASSERT(this == aSheet->GetParentSheet(),
-             "We are being notified of a sheet load for a sheet that is not "
-             "our child!");
+  MOZ_DIAGNOSTIC_ASSERT(this == aSheet->GetParentSheet(),
+                        "We are being notified of a sheet load for a sheet "
+                        "that is not our child!");
   if (NS_FAILED(aStatus)) {
     return NS_OK;
   }
-
-  MOZ_ASSERT(aSheet->GetOwnerRule());
-  NOTIFY(ImportRuleLoaded, (*aSheet->GetOwnerRule(), *aSheet));
+  // The assert below should hold if we stop triggering import loads for invalid
+  // insertRule() calls, see bug 1914106.
+  // MOZ_ASSERT(aSheet->GetOwnerRule());
+  if (!aSheet->GetOwnerRule()) {
+    return NS_OK;
+  }
+  NOTIFY(ImportRuleLoaded, (*aSheet));
   return NS_OK;
 }
 


=====================================
netwerk/ipc/DocumentLoadListener.cpp
=====================================
@@ -2316,15 +2316,9 @@ bool DocumentLoadListener::DocShellWillDisplayContent(nsresult aStatus) {
 
   auto* loadingContext = GetLoadingBrowsingContext();
 
-  bool isInitialDocument = true;
-  if (WindowGlobalParent* currentWindow =
-          loadingContext->GetCurrentWindowGlobal()) {
-    isInitialDocument = currentWindow->IsInitialDocument();
-  }
-
   nsresult rv = nsDocShell::FilterStatusForErrorPage(
       aStatus, mChannel, mLoadStateLoadType, loadingContext->IsTop(),
-      loadingContext->GetUseErrorPages(), isInitialDocument, nullptr);
+      loadingContext->GetUseErrorPages(), nullptr);
 
   if (NS_SUCCEEDED(rv)) {
     MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,


=====================================
netwerk/protocol/webtransport/WebTransportSessionProxy.cpp
=====================================
@@ -1042,15 +1042,6 @@ void WebTransportSessionProxy::NotifyDatagramReceived(
     MutexAutoLock lock(mMutex);
     MOZ_ASSERT(mTarget->IsOnCurrentThread());
 
-    if (!mStopRequestCalled) {
-      CopyableTArray<uint8_t> copied(aData);
-      mPendingEvents.AppendElement(
-          [self = RefPtr{this}, data = std::move(copied)]() mutable {
-            self->NotifyDatagramReceived(std::move(data));
-          });
-      return;
-    }
-
     if (mState != WebTransportSessionProxyState::ACTIVE || !mListener) {
       return;
     }
@@ -1066,6 +1057,15 @@ NS_IMETHODIMP WebTransportSessionProxy::OnDatagramReceivedInternal(
 
   {
     MutexAutoLock lock(mMutex);
+    if (!mStopRequestCalled) {
+      CopyableTArray<uint8_t> copied(aData);
+      mPendingEvents.AppendElement(
+          [self = RefPtr{this}, data = std::move(copied)]() mutable {
+            self->OnDatagramReceivedInternal(std::move(data));
+          });
+      return NS_OK;
+    }
+
     if (!mTarget->IsOnCurrentThread()) {
       return mTarget->Dispatch(NS_NewRunnableFunction(
           "WebTransportSessionProxy::OnDatagramReceived",


=====================================
testing/web-platform/tests/css/cssom/insertRule-import-trailing-garbage-crash.html
=====================================
@@ -0,0 +1,6 @@
+<!doctype html>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1914106">
+<style></style>
+<script>
+document.querySelector("style").sheet.insertRule("@import url('data:text/css,:root{background:red}');html,body{/* random garbage */}");
+</script>



View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/4dd63a6046c2546ee3a6399afe177069bac527fb...0fe417ba0bac85725c182328b17e6670bc58b534

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/4dd63a6046c2546ee3a6399afe177069bac527fb...0fe417ba0bac85725c182328b17e6670bc58b534
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-commits/attachments/20240930/db7c7326/attachment-0001.htm>


More information about the tor-commits mailing list