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_castmozilla::ipc::IProtocol*(aOriginProcess) - : static_castmozilla::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/4dd...
tor-commits@lists.torproject.org