Version in base suite: 140.8.0esr-1~deb13u1 Version in overlay suite: 140.9.0esr-1~deb13u1 Base version: firefox-esr_140.9.0esr-1~deb13u1 Target version: firefox-esr_140.9.1esr-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/f/firefox-esr/firefox-esr_140.9.0esr-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/f/firefox-esr/firefox-esr_140.9.1esr-1~deb13u1.dsc accessible/ipc/DocAccessibleParent.cpp | 1 browser/config/version.txt | 2 browser/config/version_display.txt | 2 config/milestone.txt | 2 debian/changelog | 8 + dom/base/Document.cpp | 10 - dom/base/nsGlobalWindowInner.cpp | 4 dom/base/nsGlobalWindowInner.h | 4 dom/base/nsINode.cpp | 6 dom/base/nsPIDOMWindow.h | 1 dom/bindings/BindingUtils.cpp | 12 + dom/canvas/CanvasRenderingContext2D.cpp | 9 - dom/canvas/ClientWebGLContext.cpp | 20 +- dom/canvas/WebGLContextGL.cpp | 12 + dom/clients/manager/ClientManagerChild.cpp | 5 dom/clients/manager/ClientNavigateOpChild.cpp | 17 +- dom/clients/manager/ClientNavigateOpChild.h | 6 dom/clients/manager/ClientSource.cpp | 46 +++++- dom/fetch/FetchParent.cpp | 3 dom/fetch/FetchParent.h | 1 dom/html/HTMLFieldSetElement.cpp | 5 dom/html/HTMLFieldSetElement.h | 2 dom/html/HTMLSelectElement.cpp | 65 +------- dom/html/HTMLSelectElement.h | 5 dom/indexedDB/ActorsParent.cpp | 16 ++ dom/indexedDB/FileInfoImpl.h | 2 dom/media/ADTSDemuxer.cpp | 2 dom/media/eme/MediaEncryptedEvent.cpp | 3 dom/media/eme/MediaKeyMessageEvent.cpp | 3 dom/media/platforms/agnostic/bytestreams/H265.cpp | 18 ++ dom/media/platforms/ffmpeg/FFmpegAudioEncoder.cpp | 7 dom/media/webcodecs/ImageDecoder.cpp | 29 ++- dom/script/ScriptElement.cpp | 13 + dom/streams/ReadableByteStreamController.cpp | 5 dom/streams/UnderlyingSourceCallbackHelpers.cpp | 12 + dom/svg/SVGFragmentIdentifier.cpp | 2 dom/worklet/WorkletFetchHandler.cpp | 10 - dom/worklet/loader/WorkletModuleLoader.cpp | 7 dom/worklet/loader/WorkletModuleLoader.h | 9 - dom/xhr/XMLHttpRequestMainThread.cpp | 5 dom/xhr/XMLHttpRequestMainThread.h | 11 - gfx/layers/RemoteTextureMap.cpp | 2 gfx/layers/wr/WebRenderBridgeParent.cpp | 17 +- gfx/ots/src/cff.cc | 17 +- gfx/ots/src/colr.cc | 20 -- image/decoders/nsBMPDecoder.cpp | 13 + image/decoders/nsBMPDecoder.h | 4 image/decoders/nsICODecoder.cpp | 62 ++++++-- js/src/builtin/temporal/Instant.cpp | 4 js/src/vm/StructuredClone.cpp | 1 layout/generic/ScrollContainerFrame.cpp | 5 layout/style/FontFace.cpp | 34 +--- layout/style/FontFaceImpl.cpp | 44 +++--- layout/style/FontFaceImpl.h | 3 layout/style/FontFaceSetImpl.cpp | 15 -- layout/style/PostTraversalTask.cpp | 13 - layout/style/PostTraversalTask.h | 42 ----- layout/tables/celldata.h | 9 + layout/tables/nsCellMap.cpp | 10 - media/libpng/ANNOUNCE | 49 +++++- media/libpng/AUTHORS | 3 media/libpng/CHANGES | 31 ++++ media/libpng/README | 2 media/libpng/arm/palette_neon_intrinsics.c | 61 +++----- media/libpng/libpng-manual.txt | 10 - media/libpng/moz.yaml | 5 media/libpng/png.c | 16 +- media/libpng/png.h | 16 +- media/libpng/pngconf.h | 2 media/libpng/pngpriv.h | 4 media/libpng/pngread.c | 68 ++++----- media/libpng/pngrtran.c | 30 +++- media/libpng/pngrutil.c | 42 ++--- media/libpng/pngset.c | 73 ++++++---- media/libpng/pngstruct.h | 6 media/libpng/pngtrans.c | 40 ++++- media/libpng/pngwrite.c | 16 +- media/libpng/pngwutil.c | 49 ------ netwerk/cookie/CookieStorage.cpp | 14 + netwerk/dns/DNSPacket.cpp | 7 sourcestamp.txt | 4 testing/web-platform/meta/fedcm/lfedcm-identity.create-store-collect.tentative.sub.https.html.ini | 3 82 files changed, 741 insertions(+), 527 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1sfoa9ws/firefox-esr_140.9.0esr-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1sfoa9ws/firefox-esr_140.9.1esr-1~deb13u1.dsc: no acceptable signature found diff -Nru firefox-esr-140.9.0esr/accessible/ipc/DocAccessibleParent.cpp firefox-esr-140.9.1esr/accessible/ipc/DocAccessibleParent.cpp --- firefox-esr-140.9.0esr/accessible/ipc/DocAccessibleParent.cpp 2026-03-17 09:42:08.000000000 +0000 +++ firefox-esr-140.9.1esr/accessible/ipc/DocAccessibleParent.cpp 2026-04-03 15:52:18.000000000 +0000 @@ -906,7 +906,6 @@ MOZ_ASSERT(CheckDocTree()); auto childDoc = static_cast(aChildDoc.get()); - childDoc->Unbind(); ipc::IPCResult result = AddChildDoc(childDoc, aID, false); MOZ_ASSERT(result); MOZ_ASSERT(CheckDocTree()); diff -Nru firefox-esr-140.9.0esr/browser/config/version.txt firefox-esr-140.9.1esr/browser/config/version.txt --- firefox-esr-140.9.0esr/browser/config/version.txt 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/browser/config/version.txt 2026-04-03 15:52:19.000000000 +0000 @@ -1 +1 @@ -140.9.0 +140.9.1 diff -Nru firefox-esr-140.9.0esr/browser/config/version_display.txt firefox-esr-140.9.1esr/browser/config/version_display.txt --- firefox-esr-140.9.0esr/browser/config/version_display.txt 2026-03-17 09:42:08.000000000 +0000 +++ firefox-esr-140.9.1esr/browser/config/version_display.txt 2026-04-03 15:52:18.000000000 +0000 @@ -1 +1 @@ -140.9.0esr +140.9.1esr diff -Nru firefox-esr-140.9.0esr/config/milestone.txt firefox-esr-140.9.1esr/config/milestone.txt --- firefox-esr-140.9.0esr/config/milestone.txt 2026-03-17 09:42:08.000000000 +0000 +++ firefox-esr-140.9.1esr/config/milestone.txt 2026-04-03 15:52:19.000000000 +0000 @@ -10,4 +10,4 @@ # hardcoded milestones in the tree from these two files. #-------------------------------------------------------- -140.9.0 +140.9.1 diff -Nru firefox-esr-140.9.0esr/debian/changelog firefox-esr-140.9.1esr/debian/changelog --- firefox-esr-140.9.0esr/debian/changelog 2026-03-24 23:43:49.000000000 +0000 +++ firefox-esr-140.9.1esr/debian/changelog 2026-04-07 22:01:40.000000000 +0000 @@ -1,3 +1,11 @@ +firefox-esr (140.9.1esr-1~deb13u1) trixie-security; urgency=medium + + * New upstream release. + * Fixes for mfsa2026-27, also known as: + CVE-2026-5732, CVE-2026-5731, CVE-2026-5734. + + -- Mike Hommey Wed, 08 Apr 2026 07:01:40 +0900 + firefox-esr (140.9.0esr-1~deb13u1) trixie-security; urgency=medium * New upstream release. diff -Nru firefox-esr-140.9.0esr/dom/base/Document.cpp firefox-esr-140.9.1esr/dom/base/Document.cpp --- firefox-esr-140.9.0esr/dom/base/Document.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/base/Document.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -10664,23 +10664,25 @@ mozilla::DebugOnly rv = element->UnsetAttr(attr->NodeInfo()->NamespaceID(), - attr->NodeInfo()->NameAtom(), false); + attr->NodeInfo()->NameAtom(), true); // XXX Should we abort here? NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!"); } } - if (mozilla::dom::ShadowRoot* shadow = element->GetShadowRoot()) { + // Hold the strong reference to be sure, since we may notify + if (RefPtr shadow = element->GetShadowRoot()) { BlastSubtreeToPieces(shadow); element->UnattachShadow(); } } while (aNode->HasChildren()) { - nsIContent* node = aNode->GetFirstChild(); + // Hold the strong reference to be sure, since we are notifying. + nsCOMPtr node = aNode->GetFirstChild(); BlastSubtreeToPieces(node); - aNode->RemoveChildNode(node, false); + aNode->RemoveChildNode(node, true); } } diff -Nru firefox-esr-140.9.0esr/dom/base/nsGlobalWindowInner.cpp firefox-esr-140.9.1esr/dom/base/nsGlobalWindowInner.cpp --- firefox-esr-140.9.0esr/dom/base/nsGlobalWindowInner.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/base/nsGlobalWindowInner.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -2535,6 +2535,10 @@ return nsGlobalWindowInner::Cast(this)->GetController(); } +ClientSource* nsPIDOMWindowInner::GetClientSource() const { + return nsGlobalWindowInner::Cast(this)->GetClientSource(); +} + void nsPIDOMWindowInner::SetCsp(nsIContentSecurityPolicy* aCsp) { return nsGlobalWindowInner::Cast(this)->SetCsp(aCsp); } diff -Nru firefox-esr-140.9.0esr/dom/base/nsGlobalWindowInner.h firefox-esr-140.9.1esr/dom/base/nsGlobalWindowInner.h --- firefox-esr-140.9.0esr/dom/base/nsGlobalWindowInner.h 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/base/nsGlobalWindowInner.h 2026-04-03 15:52:20.000000000 +0000 @@ -1286,6 +1286,10 @@ void SetCurrentPasteDataTransfer(mozilla::dom::DataTransfer* aDataTransfer); mozilla::dom::DataTransfer* GetCurrentPasteDataTransfer() const; + mozilla::dom::ClientSource* GetClientSource() const { + return mClientSource.get(); + } + private: RefPtr mContentMediaController; diff -Nru firefox-esr-140.9.0esr/dom/base/nsINode.cpp firefox-esr-140.9.1esr/dom/base/nsINode.cpp --- firefox-esr-140.9.0esr/dom/base/nsINode.cpp 2026-03-17 09:42:08.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/base/nsINode.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -3721,8 +3721,10 @@ JSAutoRealm ar(cx, wrapper); UpdateReflectorGlobal(cx, wrapper, aError); if (aError.Failed()) { + bool needsRollBack = false; if (wasRegistered) { - newDoc->UnregisterActivityObserver(aNode->AsElement()); + needsRollBack = + newDoc->UnregisterActivityObserver(aNode->AsElement()); } if (hadProperties) { // NOTE: When it fails it removes all properties for the node @@ -3732,7 +3734,7 @@ } aNode->mNodeInfo.swap(newNodeInfo); aNode->NodeInfoChanged(newDoc); - if (wasRegistered) { + if (needsRollBack) { oldDoc->RegisterActivityObserver(aNode->AsElement()); } return nullptr; diff -Nru firefox-esr-140.9.0esr/dom/base/nsPIDOMWindow.h firefox-esr-140.9.1esr/dom/base/nsPIDOMWindow.h --- firefox-esr-140.9.0esr/dom/base/nsPIDOMWindow.h 2026-03-17 09:42:08.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/base/nsPIDOMWindow.h 2026-04-03 15:52:19.000000000 +0000 @@ -366,6 +366,7 @@ mozilla::Maybe GetClientInfo() const; mozilla::Maybe GetClientState() const; mozilla::Maybe GetController() const; + mozilla::dom::ClientSource* GetClientSource() const; void SetCsp(nsIContentSecurityPolicy* aCsp); void SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCsp); diff -Nru firefox-esr-140.9.0esr/dom/bindings/BindingUtils.cpp firefox-esr-140.9.1esr/dom/bindings/BindingUtils.cpp --- firefox-esr-140.9.0esr/dom/bindings/BindingUtils.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/bindings/BindingUtils.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -2483,6 +2483,18 @@ JS::SetReservedSlot(newobj, DOM_OBJECT_SLOT, JS::GetReservedSlot(aObj, DOM_OBJECT_SLOT)); JS::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr)); + size_t nslots = JSCLASS_RESERVED_SLOTS(JS::GetClass(aObj)); + for (size_t slot = DOM_INSTANCE_RESERVED_SLOTS; slot < nslots; ++slot) { + const JS::Value& slotValue = JS::GetReservedSlot(aObj, slot); + if (slotValue.isObject()) { + JSObject* slotObj = &slotValue.toObject(); + if (IsObservableArrayProxy(slotObj)) { + JS::SetReservedSlot(newobj, slot, slotValue); + JS::SetReservedSlot(aObj, slot, JS::UndefinedValue()); + } + } + } + nsWrapperCache* cache = nullptr; CallQueryInterface(native, &cache); cache->UpdateWrapperForNewGlobal(native, newobj); diff -Nru firefox-esr-140.9.0esr/dom/canvas/CanvasRenderingContext2D.cpp firefox-esr-140.9.1esr/dom/canvas/CanvasRenderingContext2D.cpp --- firefox-esr-140.9.0esr/dom/canvas/CanvasRenderingContext2D.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/canvas/CanvasRenderingContext2D.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -3434,6 +3434,11 @@ return; } + const bool needBounds = NeedToCalculateBounds(); + if (!IsTargetValid()) { + return; + } + const ContextState* state = &CurrentState(); StrokeOptions strokeOptions(state->lineWidth, CanvasToGfx(state->lineJoin), CanvasToGfx(state->lineCap), state->miterLimit, @@ -3441,10 +3446,6 @@ state->dashOffset); state = nullptr; - const bool needBounds = NeedToCalculateBounds(); - if (!IsTargetValid()) { - return; - } gfx::Rect bounds; if (needBounds) { bounds = aPath.GetStrokedBounds(strokeOptions, mTarget->GetTransform()); diff -Nru firefox-esr-140.9.0esr/dom/canvas/ClientWebGLContext.cpp firefox-esr-140.9.1esr/dom/canvas/ClientWebGLContext.cpp --- firefox-esr-140.9.0esr/dom/canvas/ClientWebGLContext.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/canvas/ClientWebGLContext.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -198,7 +198,19 @@ : mIsWebGL2(webgl2), mExtLoseContext(new ClientWebGLExtensionLoseContext(*this)) {} -ClientWebGLContext::~ClientWebGLContext() { RemovePostRefreshObserver(); } +static inline void SafeReleaseNotLostData( + std::shared_ptr& notLost) { + if (notLost) { + const auto keepAlive = std::move(notLost); + keepAlive->extensions = {}; + keepAlive->state = {}; + } +} + +ClientWebGLContext::~ClientWebGLContext() { + RemovePostRefreshObserver(); + SafeReleaseNotLostData(mNotLost); +} void ClientWebGLContext::JsWarning(const std::string& utf8) const { nsIGlobalObject* global = nullptr; @@ -7004,11 +7016,7 @@ } void ImplCycleCollectionUnlink(std::shared_ptr& field) { - if (!field) return; - const auto keepAlive = field; - keepAlive->extensions = {}; - keepAlive->state = {}; - field = nullptr; + SafeReleaseNotLostData(field); } // ----------------------------------------------------- diff -Nru firefox-esr-140.9.0esr/dom/canvas/WebGLContextGL.cpp firefox-esr-140.9.1esr/dom/canvas/WebGLContextGL.cpp --- firefox-esr-140.9.0esr/dom/canvas/WebGLContextGL.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/canvas/WebGLContextGL.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -1133,6 +1133,18 @@ ////// + // Reject invalid pack alignment. + switch (desc.packState.alignmentInTypeElems) { + case 1: + case 2: + case 4: + case 8: + break; // all good + default: + ErrorInvalidValue("pack alignment must be 1, 2, 4, or 8."); + return {}; + } + const auto& srcOffset = desc.srcOffset; const auto& size = desc.size; diff -Nru firefox-esr-140.9.0esr/dom/clients/manager/ClientManagerChild.cpp firefox-esr-140.9.1esr/dom/clients/manager/ClientManagerChild.cpp --- firefox-esr-140.9.0esr/dom/clients/manager/ClientManagerChild.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/clients/manager/ClientManagerChild.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -55,8 +55,9 @@ mozilla::ipc::IPCResult ClientManagerChild::RecvPClientNavigateOpConstructor( PClientNavigateOpChild* aActor, const ClientNavigateOpConstructorArgs& aArgs) { - auto actor = static_cast(aActor); - actor->Init(aArgs); + RefPtr proxy = aActor->GetLifecycleProxy(); + auto* actor = static_cast(aActor); + actor->Init(aArgs, proxy); return IPC_OK(); } diff -Nru firefox-esr-140.9.0esr/dom/clients/manager/ClientNavigateOpChild.cpp firefox-esr-140.9.1esr/dom/clients/manager/ClientNavigateOpChild.cpp --- firefox-esr-140.9.0esr/dom/clients/manager/ClientNavigateOpChild.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/clients/manager/ClientNavigateOpChild.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -152,7 +152,8 @@ } // anonymous namespace RefPtr ClientNavigateOpChild::DoNavigate( - const ClientNavigateOpConstructorArgs& aArgs) { + const ClientNavigateOpConstructorArgs& aArgs, + mozilla::ipc::ActorLifecycleProxy* aProxy) { nsCOMPtr window; // Navigating the target client window will result in the original @@ -278,6 +279,12 @@ return ClientOpPromise::CreateAndReject(result, __func__); } + if (!aProxy->Get()) { + CopyableErrorResult result; + result.ThrowInvalidStateError("Unknown Client"); + return ClientOpPromise::CreateAndReject(result, __func__); + } + RefPtr promise = new ClientOpPromise::Private(__func__); @@ -305,8 +312,12 @@ mPromiseRequestHolder.DisconnectIfExists(); } -void ClientNavigateOpChild::Init(const ClientNavigateOpConstructorArgs& aArgs) { - RefPtr promise = DoNavigate(aArgs); +void ClientNavigateOpChild::Init(const ClientNavigateOpConstructorArgs& aArgs, + mozilla::ipc::ActorLifecycleProxy* aProxy) { + RefPtr promise = DoNavigate(aArgs, aProxy); + if (!aProxy->Get()) { + return; + } // Normally we get the event target from the window in DoNavigate(). If a // failure occurred, though, we may need to fall back to the current thread diff -Nru firefox-esr-140.9.0esr/dom/clients/manager/ClientNavigateOpChild.h firefox-esr-140.9.1esr/dom/clients/manager/ClientNavigateOpChild.h --- firefox-esr-140.9.0esr/dom/clients/manager/ClientNavigateOpChild.h 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/clients/manager/ClientNavigateOpChild.h 2026-04-03 15:52:20.000000000 +0000 @@ -16,7 +16,8 @@ nsCOMPtr mSerialEventTarget; [[nodiscard]] RefPtr DoNavigate( - const ClientNavigateOpConstructorArgs& aArgs); + const ClientNavigateOpConstructorArgs& aArgs, + mozilla::ipc::ActorLifecycleProxy* aProxy); // PClientNavigateOpChild interface void ActorDestroy(ActorDestroyReason aReason) override; @@ -25,7 +26,8 @@ ClientNavigateOpChild() = default; ~ClientNavigateOpChild() = default; - void Init(const ClientNavigateOpConstructorArgs& aArgs); + void Init(const ClientNavigateOpConstructorArgs& aArgs, + mozilla::ipc::ActorLifecycleProxy* aProxy); }; } // namespace mozilla::dom diff -Nru firefox-esr-140.9.0esr/dom/clients/manager/ClientSource.cpp firefox-esr-140.9.1esr/dom/clients/manager/ClientSource.cpp --- firefox-esr-140.9.0esr/dom/clients/manager/ClientSource.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/clients/manager/ClientSource.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -520,11 +520,12 @@ return ClientOpPromise::CreateAndReject(rv, __func__); } nsCOMPtr outer; - nsPIDOMWindowInner* inner = GetInnerWindow(); + nsCOMPtr inner = GetInnerWindow(); + nsIDocShell* docshell = nullptr; if (inner) { outer = inner->GetOuterWindow(); } else { - nsIDocShell* docshell = GetDocShell(); + docshell = GetDocShell(); if (docshell) { outer = docshell->GetWindow(); } @@ -537,9 +538,48 @@ } MOZ_ASSERT(NS_IsMainThread()); + + // Inlined from `ClientSource::SnapshotWindowState()`: + // Should not be necessary after bug 543435. Clean this up in bug 2025284. + if (docshell) { + // Force the creation of the initial document if it does not yet exist. + if (!docshell->GetDocument()) { + CopyableErrorResult rv; + rv.ThrowInvalidStateError("No document available."); + return ClientOpPromise::CreateAndReject(rv, __func__); + } + inner = GetInnerWindow(); + } + nsFocusManager::FocusWindow(outer, aArgs.callerType()); - Result state = SnapshotState(); + Result state = + [&]() -> Result { + if (!inner) { + // Inlined from `ClientSource::SnapshotWindowState()`: + return ClientState(ClientWindowState(VisibilityState::Hidden, TimeStamp(), + StorageAccess::eDeny, false)); + } + if (inner->GetClientSource() == this) { + // The pointer comparison assumes that an inner window + // cannot gain a new ClientSource other than this same + // `ClientSource` having moved from a docshell owner to an + // inner window owner gained via `outer`, so we don't need to worry + // about a newly-allocated ClientSource occupying the same + // memory as the one pointed to by `this`. That is, in the case + // of the pointers being unequal, `inner->GetClientSource()` + // returns `nullptr` and `this` is an invalid pointer. + // Per [expr.eq], it's not UB to compare a pointer to a deleted + // object, since no pointer comparisons are UB anymore. The + // case about pointer-past-end for a different object being + // _unspecified_ behavior does not apply here. + return SnapshotState(); + } + ErrorResult rv; + rv.ThrowInvalidStateError("Client destroyed during focus"); + return Err(std::move(rv)); + }(); + if (state.isErr()) { return ClientOpPromise::CreateAndReject( CopyableErrorResult(state.unwrapErr()), __func__); diff -Nru firefox-esr-140.9.0esr/dom/fetch/FetchParent.cpp firefox-esr-140.9.1esr/dom/fetch/FetchParent.cpp --- firefox-esr-140.9.0esr/dom/fetch/FetchParent.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/fetch/FetchParent.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -89,6 +89,9 @@ FETCH_LOG(("FetchParent::RecvFetchOp [%p]", this)); AssertIsOnBackgroundThread(); + if (mReceivedFetchOp.exchange(true)) { + return IPC_FAIL(this, "FetchOp received more than once on this actor"); + } MOZ_ASSERT(!mIsDone); if (mActorDestroyed) { return IPC_OK(); diff -Nru firefox-esr-140.9.0esr/dom/fetch/FetchParent.h firefox-esr-140.9.1esr/dom/fetch/FetchParent.h --- firefox-esr-140.9.0esr/dom/fetch/FetchParent.h 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/fetch/FetchParent.h 2026-04-03 15:52:19.000000000 +0000 @@ -103,6 +103,7 @@ Atomic mIsDone{false}; Atomic mActorDestroyed{false}; + Atomic mReceivedFetchOp{false}; nsCOMPtr mBackgroundEventTarget; }; diff -Nru firefox-esr-140.9.0esr/dom/html/HTMLFieldSetElement.cpp firefox-esr-140.9.1esr/dom/html/HTMLFieldSetElement.cpp --- firefox-esr-140.9.0esr/dom/html/HTMLFieldSetElement.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/html/HTMLFieldSetElement.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -23,7 +23,6 @@ : nsGenericHTMLFormControlElement(std::move(aNodeInfo), FormControlType::Fieldset), mElements(nullptr), - mFirstLegend(nullptr), mInvalidElementsCount(0) { //
is always barred from constraint validation. SetBarredFromConstraintValidation(true); @@ -41,7 +40,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLFieldSetElement, nsGenericHTMLFormControlElement, mValidity, - mElements) + mElements, mFirstLegend) NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLFieldSetElement, nsGenericHTMLFormControlElement, @@ -110,6 +109,7 @@ nsIContent* aBeforeThis, bool aNotify, ErrorResult& aRv) { bool firstLegendHasChanged = false; + RefPtr oldFirstLegend = mFirstLegend; if (aChild->IsHTMLElement(nsGkAtoms::legend)) { if (!mFirstLegend) { @@ -134,6 +134,7 @@ nsGenericHTMLFormControlElement::InsertChildBefore(aChild, aBeforeThis, aNotify, aRv); if (aRv.Failed()) { + mFirstLegend = oldFirstLegend; return; } diff -Nru firefox-esr-140.9.0esr/dom/html/HTMLFieldSetElement.h firefox-esr-140.9.1esr/dom/html/HTMLFieldSetElement.h --- firefox-esr-140.9.0esr/dom/html/HTMLFieldSetElement.h 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/html/HTMLFieldSetElement.h 2026-04-03 15:52:19.000000000 +0000 @@ -126,7 +126,7 @@ // List of elements which have this fieldset as first fieldset ancestor. nsTArray mDependentElements; - nsIContent* mFirstLegend; + RefPtr mFirstLegend; /** * Number of invalid and candidate for constraint validation diff -Nru firefox-esr-140.9.0esr/dom/html/HTMLSelectElement.cpp firefox-esr-140.9.1esr/dom/html/HTMLSelectElement.cpp --- firefox-esr-140.9.0esr/dom/html/HTMLSelectElement.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/html/HTMLSelectElement.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -299,24 +299,10 @@ OnSelectionChanged(); } - // Get the frame stuff for notification. No need to flush here - // since if there's no frame for the select yet the select will - // get into the right state once it's created. - nsISelectControlFrame* selectFrame = nullptr; - AutoWeakFrame weakSelectFrame; - bool didGetFrame = false; - // Actually select the options if the added options warrant it for (int32_t i = aListIndex; i < insertIndex; i++) { - // Notify the frame that the option is added - if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) { - selectFrame = GetSelectFrame(); - weakSelectFrame = do_QueryFrame(selectFrame); - didGetFrame = true; - } - - if (selectFrame) { - selectFrame->AddOption(i); + if (auto* frame = GetSelectFrame()) { + frame->AddOption(i); } RefPtr option = Item(i); @@ -332,7 +318,7 @@ // This is sort of a hack ... we need to notify that the option was // set and change selectedIndex even though we didn't really change // its value. - OnOptionSelected(selectFrame, i, true, false, aNotify); + OnOptionSelected(i, true, false, aNotify); } } @@ -715,8 +701,7 @@ return option && option->Selected(); } -void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame, - int32_t aIndex, bool aSelected, +void HTMLSelectElement::OnOptionSelected(int32_t aIndex, bool aSelected, bool aChangeOptionState, bool aNotify) { // Set the selected index @@ -736,8 +721,8 @@ } // Let the frame know too - if (aSelectFrame) { - aSelectFrame->OnOptionSelected(aIndex, aSelected); + if (auto* frame = GetSelectFrame()) { + frame->OnOptionSelected(aIndex, aSelected); } UpdateSelectedOptions(); @@ -808,10 +793,6 @@ bool optionsSelected = false; bool optionsDeselected = false; - nsISelectControlFrame* selectFrame = nullptr; - bool didGetFrame = false; - AutoWeakFrame weakSelectFrame; - if (aOptionsMask.contains(OptionFlag::IsSelected)) { // Setting selectedIndex to an out-of-bounds index means -1. (HTML5) if (aStartIndex < 0 || AssertedCast(aStartIndex) >= numItems || @@ -861,15 +842,7 @@ // the option has just been inserted we have to get in sync with it. if (option && (aOptionsMask.contains(OptionFlag::InsertingOptions) || !option->Selected())) { - // To notify the frame if anything gets changed. No need - // to flush here, if there's no frame yet we don't need to - // force it to be created just to notify it about a change - // in the select. - selectFrame = GetSelectFrame(); - weakSelectFrame = do_QueryFrame(selectFrame); - didGetFrame = true; - - OnOptionSelected(selectFrame, optIndex, true, !option->Selected(), + OnOptionSelected(optIndex, true, !option->Selected(), aOptionsMask.contains(OptionFlag::Notify)); optionsSelected = true; } @@ -889,17 +862,7 @@ HTMLOptionElement* option = Item(optIndex); // If the index is already deselected, ignore it. if (option && option->Selected()) { - if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) { - // To notify the frame if anything gets changed, don't - // flush, if the frame doesn't exist we don't need to - // create it just to tell it about this change. - selectFrame = GetSelectFrame(); - weakSelectFrame = do_QueryFrame(selectFrame); - - didGetFrame = true; - } - - OnOptionSelected(selectFrame, optIndex, false, true, + OnOptionSelected(optIndex, false, true, aOptionsMask.contains(OptionFlag::Notify)); optionsDeselected = true; @@ -923,17 +886,7 @@ // If the index is already selected, ignore it. if (option && option->Selected()) { - if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) { - // To notify the frame if anything gets changed, don't - // flush, if the frame doesn't exist we don't need to - // create it just to tell it about this change. - selectFrame = GetSelectFrame(); - weakSelectFrame = do_QueryFrame(selectFrame); - - didGetFrame = true; - } - - OnOptionSelected(selectFrame, optIndex, false, true, + OnOptionSelected(optIndex, false, true, aOptionsMask.contains(OptionFlag::Notify)); optionsDeselected = true; } diff -Nru firefox-esr-140.9.0esr/dom/html/HTMLSelectElement.h firefox-esr-140.9.1esr/dom/html/HTMLSelectElement.h --- firefox-esr-140.9.0esr/dom/html/HTMLSelectElement.h 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/html/HTMLSelectElement.h 2026-04-03 15:52:19.000000000 +0000 @@ -368,7 +368,6 @@ /** * Called to trigger notifications of frames and fixing selected index * - * @param aSelectFrame the frame for this content (could be null) * @param aIndex the index that was selected or deselected * @param aSelected whether the index was selected or deselected * @param aChangeOptionState if false, don't do anything to the @@ -376,8 +375,8 @@ * its selected state to aSelected. * @param aNotify whether to notify the style system and such */ - void OnOptionSelected(nsISelectControlFrame* aSelectFrame, int32_t aIndex, - bool aSelected, bool aChangeOptionState, bool aNotify); + void OnOptionSelected(int32_t aIndex, bool aSelected, bool aChangeOptionState, + bool aNotify); /** * Restore state to a particular state string (representing the options) * @param aNewSelected the state string to restore to diff -Nru firefox-esr-140.9.0esr/dom/indexedDB/ActorsParent.cpp firefox-esr-140.9.1esr/dom/indexedDB/ActorsParent.cpp --- firefox-esr-140.9.0esr/dom/indexedDB/ActorsParent.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/indexedDB/ActorsParent.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -7572,6 +7572,15 @@ mConnection->AssertIsOnConnectionThread(); MOZ_ASSERT(mInSavepoint); + // The savepoint is being committed. The deltas it contributed are now + // permanent in mDelta, so reset mSavepointDelta on each entry before + // dropping the index. The FileInfoEntry objects themselves persist in + // mFileInfoEntries across savepoints; without this reset, a stale + // mSavepointDelta would be carried into the next savepoint. + for (const auto& entry : mSavepointEntriesIndex.Values()) { + entry->ResetSavepointDelta(); + } + mSavepointEntriesIndex.Clear(); mInSavepoint = false; } @@ -10329,6 +10338,13 @@ if (NS_AUUF_OR_WARN_IF(!file)) { return false; } + + // Reject actors managed by a different Database + if (NS_AUUF_OR_WARN_IF(file->Manager() != + static_cast( + &GetDatabase()))) { + return false; + } break; case StructuredCloneFileBase::eMutableFile: { diff -Nru firefox-esr-140.9.0esr/dom/indexedDB/FileInfoImpl.h firefox-esr-140.9.1esr/dom/indexedDB/FileInfoImpl.h --- firefox-esr-140.9.0esr/dom/indexedDB/FileInfoImpl.h 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/indexedDB/FileInfoImpl.h 2026-04-03 15:52:20.000000000 +0000 @@ -74,7 +74,7 @@ aRefCount = aRefCount + aDelta; - if (mRefCnt + mDBRefCnt > 0) { + if (mRefCnt > 0 || mDBRefCnt > 0) { return; } diff -Nru firefox-esr-140.9.0esr/dom/media/ADTSDemuxer.cpp firefox-esr-140.9.1esr/dom/media/ADTSDemuxer.cpp --- firefox-esr-140.9.0esr/dom/media/ADTSDemuxer.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/media/ADTSDemuxer.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -550,7 +550,7 @@ if (mInfo && streamLen > 0) { int64_t max = streamLen > aOffset ? streamLen - aOffset : 0; // Prevent blocking reads after successful initialization. - aSize = std::min(aSize, AssertedCast(max)); + aSize = static_cast(std::min(static_cast(aSize), max)); } uint32_t read = 0; diff -Nru firefox-esr-140.9.0esr/dom/media/eme/MediaEncryptedEvent.cpp firefox-esr-140.9.1esr/dom/media/eme/MediaEncryptedEvent.cpp --- firefox-esr-140.9.0esr/dom/media/eme/MediaEncryptedEvent.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/media/eme/MediaEncryptedEvent.cpp 2026-04-03 15:52:19.000000000 +0000 @@ -28,7 +28,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaEncryptedEvent, Event) - mozilla::DropJSObjects(tmp); + tmp->mInitData = nullptr; + tmp->mRawInitData.Clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaEncryptedEvent) diff -Nru firefox-esr-140.9.0esr/dom/media/eme/MediaKeyMessageEvent.cpp firefox-esr-140.9.1esr/dom/media/eme/MediaKeyMessageEvent.cpp --- firefox-esr-140.9.0esr/dom/media/eme/MediaKeyMessageEvent.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/media/eme/MediaKeyMessageEvent.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -31,7 +31,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaKeyMessageEvent, Event) - mozilla::DropJSObjects(tmp); + tmp->mMessage = nullptr; + tmp->mRawMessage.Clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeyMessageEvent) diff -Nru firefox-esr-140.9.0esr/dom/media/platforms/agnostic/bytestreams/H265.cpp firefox-esr-140.9.1esr/dom/media/platforms/agnostic/bytestreams/H265.cpp --- firefox-esr-140.9.0esr/dom/media/platforms/agnostic/bytestreams/H265.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/media/platforms/agnostic/bytestreams/H265.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -630,6 +630,8 @@ if (aStRpsIdx != 0) { inter_ref_pic_set_prediction_flag = aReader.ReadBit(); } + const uint32_t spsMaxDecPicBufferingMinus1 = + aSPS.sps_max_dec_pic_buffering_minus1[aSPS.sps_max_sub_layers_minus1]; if (inter_ref_pic_set_prediction_flag) { int delta_idx_minus1 = 0; if (aStRpsIdx == aSPS.num_short_term_ref_pic_sets) { @@ -707,11 +709,20 @@ } } curStRefPicSet.num_positive_pics = i; + // 7.4.8 - num_negative_pics shall be in the range of 0 to + // sps_max_dec_pic_buffering_minus1[sps_max_sub_layers_minus1], inclusive. + // num_positive_pics shall be in the range of 0 to + // sps_max_dec_pic_buffering_minus1[sps_max_sub_layers_minus1] - + // num_negative_pics, inclusive. + IN_RANGE_OR_RETURN(curStRefPicSet.num_negative_pics, 0, + spsMaxDecPicBufferingMinus1); + CheckedUint32 maxPositivePics{spsMaxDecPicBufferingMinus1}; + maxPositivePics -= curStRefPicSet.num_negative_pics; + IN_RANGE_OR_RETURN(curStRefPicSet.num_positive_pics, 0, + maxPositivePics.value()); } else { curStRefPicSet.num_negative_pics = aReader.ReadUE(); curStRefPicSet.num_positive_pics = aReader.ReadUE(); - const uint32_t spsMaxDecPicBufferingMinus1 = - aSPS.sps_max_dec_pic_buffering_minus1[aSPS.sps_max_sub_layers_minus1]; IN_RANGE_OR_RETURN(curStRefPicSet.num_negative_pics, 0, spsMaxDecPicBufferingMinus1); CheckedUint32 maxPositivePics{spsMaxDecPicBufferingMinus1}; @@ -748,6 +759,9 @@ // (7-71) curStRefPicSet.numDeltaPocs = curStRefPicSet.num_negative_pics + curStRefPicSet.num_positive_pics; + // 7.4.8 - NumDeltaPocs = num_negative_pics + num_positive_pics counts DPB + // entries, bounded by sps_max_dec_pic_buffering_minus1. + IN_RANGE_OR_RETURN(curStRefPicSet.numDeltaPocs, 0, spsMaxDecPicBufferingMinus1); return Ok(); } diff -Nru firefox-esr-140.9.0esr/dom/media/platforms/ffmpeg/FFmpegAudioEncoder.cpp firefox-esr-140.9.1esr/dom/media/platforms/ffmpeg/FFmpegAudioEncoder.cpp --- firefox-esr-140.9.0esr/dom/media/platforms/ffmpeg/FFmpegAudioEncoder.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/media/platforms/ffmpeg/FFmpegAudioEncoder.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -300,10 +300,9 @@ aSamples.Length()); } else { MOZ_ASSERT(mCodecContext->sample_fmt == AV_SAMPLE_FMT_FLTP); - for (uint32_t i = 0; i < mConfig.mNumberOfChannels; i++) { - DeinterleaveAndConvertBuffer(aSamples.data(), mFrame->nb_samples, - mConfig.mNumberOfChannels, mFrame->data); - } + DeinterleaveAndConvertBuffer(aSamples.data(), mFrame->nb_samples, + mConfig.mNumberOfChannels, + mFrame->extended_data); } // Now send the AVFrame to ffmpeg for encoding, same code for audio and video. diff -Nru firefox-esr-140.9.0esr/dom/media/webcodecs/ImageDecoder.cpp firefox-esr-140.9.1esr/dom/media/webcodecs/ImageDecoder.cpp --- firefox-esr-140.9.0esr/dom/media/webcodecs/ImageDecoder.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/media/webcodecs/ImageDecoder.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -340,7 +340,7 @@ return; } - ImageTrack* track = mTracks->GetDefaultTrack(); + RefPtr track = mTracks->GetDefaultTrack(); if (!track) { return; } @@ -410,19 +410,31 @@ // 4. Resolve promise with result. for (const auto& i : resolved) { - ImageDecodeResult result; - result.mImage = track->GetDecodedFrame(i.mFrameIndex); - // TODO(aosmond): progressive images - result.mComplete = true; - i.mPromise->MaybeResolve(result); + if (!mClosed) { + ImageDecodeResult result; + result.mImage = track->GetDecodedFrame(i.mFrameIndex); + // TODO(aosmond): progressive images + result.mComplete = true; + i.mPromise->MaybeResolve(result); + } else { + i.mPromise->MaybeRejectWithAbortError("Closed decoder"_ns); + } } for (const auto& i : rejectedRange) { - i.mPromise->MaybeRejectWithRangeError("No more frames available"_ns); + if (!mClosed) { + i.mPromise->MaybeRejectWithRangeError("No more frames available"_ns); + } else { + i.mPromise->MaybeRejectWithAbortError("Closed decoder"_ns); + } } for (const auto& i : rejectedState) { - i.mPromise->MaybeRejectWithInvalidStateError("Error decoding frame"_ns); + if (!mClosed) { + i.mPromise->MaybeRejectWithInvalidStateError("Error decoding frame"_ns); + } else { + i.mPromise->MaybeRejectWithAbortError("Closed decoder"_ns); + } } } @@ -994,6 +1006,7 @@ } void ImageDecoder::Close(const MediaResult& aResult) { + RefPtr kungFuDeathGrip(this); MOZ_LOG(gWebCodecsLog, LogLevel::Debug, ("ImageDecoder %p Close", this)); // 10.2.5. Algorithms - Close ImageDecoder (with exception) diff -Nru firefox-esr-140.9.0esr/dom/script/ScriptElement.cpp firefox-esr-140.9.1esr/dom/script/ScriptElement.cpp --- firefox-esr-140.9.0esr/dom/script/ScriptElement.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/script/ScriptElement.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -85,12 +85,18 @@ void ScriptElement::CharacterDataChanged(nsIContent* aContent, const CharacterDataChangeInfo&) { + if (!nsContentUtils::IsInSameAnonymousTree(GetAsContent(), aContent)) { + return; + } MaybeProcessScript(); } void ScriptElement::AttributeChanged(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType, const nsAttrValue* aOldValue) { + if (aElement != GetAsContent()) { + return; + } // https://html.spec.whatwg.org/#script-processing-model // When a script element el that is not parser-inserted experiences one of the // events listed in the following list, the user agent must immediately @@ -116,10 +122,17 @@ } void ScriptElement::ContentAppended(nsIContent* aFirstNewContent) { + if (!nsContentUtils::IsInSameAnonymousTree(GetAsContent(), + aFirstNewContent)) { + return; + } MaybeProcessScript(); } void ScriptElement::ContentInserted(nsIContent* aChild) { + if (!nsContentUtils::IsInSameAnonymousTree(GetAsContent(), aChild)) { + return; + } MaybeProcessScript(); } diff -Nru firefox-esr-140.9.0esr/dom/streams/ReadableByteStreamController.cpp firefox-esr-140.9.1esr/dom/streams/ReadableByteStreamController.cpp --- firefox-esr-140.9.0esr/dom/streams/ReadableByteStreamController.cpp 2026-03-17 09:42:09.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/streams/ReadableByteStreamController.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -1448,14 +1448,15 @@ return; } + RefPtr stream(aController->Stream()); + // Step 3.3. For each filledPullInto of filledPullIntos, for (auto& filledPullInto : filledPullIntos) { // Step 3.3.1. Perform ! // ReadableByteStreamControllerCommitPullIntoDescriptor(controller.[[stream]], // filledPullInto). ReadableByteStreamControllerCommitPullIntoDescriptor( - aCx, MOZ_KnownLive(aController->Stream()), - MOZ_KnownLive(filledPullInto), aRv); + aCx, stream, MOZ_KnownLive(filledPullInto), aRv); if (aRv.Failed()) { return; } diff -Nru firefox-esr-140.9.0esr/dom/streams/UnderlyingSourceCallbackHelpers.cpp firefox-esr-140.9.1esr/dom/streams/UnderlyingSourceCallbackHelpers.cpp --- firefox-esr-140.9.0esr/dom/streams/UnderlyingSourceCallbackHelpers.cpp 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/streams/UnderlyingSourceCallbackHelpers.cpp 2026-04-03 15:52:21.000000000 +0000 @@ -448,8 +448,10 @@ // But we do not use pullSize but use byteWritten here, since nsIInputStream // does not guarantee to read as much as it told in Available(). MOZ_DIAGNOSTIC_ASSERT(pullSize == bytesWritten); - ReadableByteStreamControllerRespond( - aCx, MOZ_KnownLive(mStream->Controller()->AsByte()), bytesWritten, aRv); + RefPtr byteController( + mStream->Controller()->AsByte()); + MOZ_ASSERT(byteController); + ReadableByteStreamControllerRespond(aCx, byteController, bytesWritten, aRv); } // Step 9. Otherwise, else { @@ -483,8 +485,10 @@ // Step 9.2. Perform ? // ReadableByteStreamControllerEnqueue(stream.[[controller]], view). - ReadableByteStreamControllerEnqueue( - aCx, MOZ_KnownLive(mStream->Controller()->AsByte()), view, aRv); + RefPtr byteController( + mStream->Controller()->AsByte()); + MOZ_ASSERT(byteController); + ReadableByteStreamControllerEnqueue(aCx, byteController, view, aRv); } } diff -Nru firefox-esr-140.9.0esr/dom/svg/SVGFragmentIdentifier.cpp firefox-esr-140.9.1esr/dom/svg/SVGFragmentIdentifier.cpp --- firefox-esr-140.9.0esr/dom/svg/SVGFragmentIdentifier.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/svg/SVGFragmentIdentifier.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -152,7 +152,7 @@ MOZ_ASSERT(aDocument->GetRootElement()->IsSVGElement(nsGkAtoms::svg), "expecting an SVG root element"); - auto* rootElement = SVGSVGElement::FromNode(aDocument->GetRootElement()); + RefPtr rootElement = SVGSVGElement::FromNode(aDocument->GetRootElement()); const auto* viewElement = SVGViewElement::FromNodeOrNull(aDocument->GetElementById(aAnchorName)); diff -Nru firefox-esr-140.9.0esr/dom/worklet/WorkletFetchHandler.cpp firefox-esr-140.9.1esr/dom/worklet/WorkletFetchHandler.cpp --- firefox-esr-140.9.0esr/dom/worklet/WorkletFetchHandler.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/worklet/WorkletFetchHandler.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -42,13 +42,13 @@ WorkletImpl* aWorkletImpl, const nsMainThreadPtrHandle& aHandlerRef, nsCOMPtr aURI, nsIURI* aReferrer, - const nsTArray& aLocalizedStrs) + nsTArray&& aLocalizedStrs) : Runnable("Worklet::StartModuleLoadRunnable"), mWorkletImpl(aWorkletImpl), mHandlerRef(aHandlerRef), mURI(std::move(aURI)), mReferrer(aReferrer), - mLocalizedStrs(aLocalizedStrs), + mLocalizedStrs(std::move(aLocalizedStrs)), mParentRuntime( JS_GetParentRuntime(CycleCollectedJSContext::Get()->Context())) { MOZ_ASSERT(NS_IsMainThread()); @@ -67,7 +67,7 @@ nsMainThreadPtrHandle mHandlerRef; nsCOMPtr mURI; nsCOMPtr mReferrer; - const nsTArray& mLocalizedStrs; + nsTArray mLocalizedStrs; JSRuntime* mParentRuntime; JS::ContextOptions mContextOptions; }; @@ -107,7 +107,7 @@ MOZ_ASSERT(moduleLoader); if (!moduleLoader->HasSetLocalizedStrings()) { - moduleLoader->SetLocalizedStrings(&mLocalizedStrs); + moduleLoader->SetLocalizedStrings(mLocalizedStrs.Clone()); } RefPtr loadContext = new WorkletLoadContext(mHandlerRef); @@ -338,7 +338,7 @@ nsIURI* referrer = doc->GetDocumentURIAsReferrer(); nsCOMPtr runnable = new StartModuleLoadRunnable( aWorklet->mImpl, handlerRef, std::move(resolvedURI), referrer, - aWorklet->GetLocalizedStrings()); + aWorklet->GetLocalizedStrings().Clone()); if (NS_FAILED(aWorklet->mImpl->SendControlMessage(runnable.forget()))) { return nullptr; diff -Nru firefox-esr-140.9.0esr/dom/worklet/loader/WorkletModuleLoader.cpp firefox-esr-140.9.1esr/dom/worklet/loader/WorkletModuleLoader.cpp --- firefox-esr-140.9.0esr/dom/worklet/loader/WorkletModuleLoader.cpp 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/worklet/loader/WorkletModuleLoader.cpp 2026-04-03 15:52:21.000000000 +0000 @@ -306,13 +306,12 @@ ResolveError aError, const nsAString& aSpecifier, nsAString& aResult) { uint8_t index = static_cast(aError); MOZ_ASSERT(index < static_cast(ResolveError::Length)); - MOZ_ASSERT(mLocalizedStrs); - MOZ_ASSERT(!mLocalizedStrs->IsEmpty()); - if (!mLocalizedStrs || NS_WARN_IF(mLocalizedStrs->IsEmpty())) { + MOZ_ASSERT(HasSetLocalizedStrings()); + if (NS_WARN_IF(mLocalizedStrs.IsEmpty())) { return NS_ERROR_FAILURE; } - const nsString& localizedStr = mLocalizedStrs->ElementAt(index); + const nsString& localizedStr = mLocalizedStrs.ElementAt(index); AutoTArray params; params.AppendElement(aSpecifier); diff -Nru firefox-esr-140.9.0esr/dom/worklet/loader/WorkletModuleLoader.h firefox-esr-140.9.1esr/dom/worklet/loader/WorkletModuleLoader.h --- firefox-esr-140.9.0esr/dom/worklet/loader/WorkletModuleLoader.h 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/worklet/loader/WorkletModuleLoader.h 2026-04-03 15:52:21.000000000 +0000 @@ -55,9 +55,10 @@ void RemoveRequest(nsIURI* aURI); JS::loader::ModuleLoadRequest* GetRequest(nsIURI* aURI) const; - bool HasSetLocalizedStrings() const { return (bool)mLocalizedStrs; } - void SetLocalizedStrings(const nsTArray* aStrings) { - mLocalizedStrs = aStrings; + bool HasSetLocalizedStrings() const { return !mLocalizedStrs.IsEmpty(); } + void SetLocalizedStrings(nsTArray&& aStrings) { + MOZ_ASSERT(!aStrings.IsEmpty()); + mLocalizedStrs = std::move(aStrings); } private: @@ -104,7 +105,7 @@ // We get the localized strings on the main thread, and pass it to // WorkletModuleLoader. - const nsTArray* mLocalizedStrs = nullptr; + nsTArray mLocalizedStrs; }; } // namespace loader diff -Nru firefox-esr-140.9.0esr/dom/xhr/XMLHttpRequestMainThread.cpp firefox-esr-140.9.1esr/dom/xhr/XMLHttpRequestMainThread.cpp --- firefox-esr-140.9.0esr/dom/xhr/XMLHttpRequestMainThread.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/xhr/XMLHttpRequestMainThread.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -313,10 +313,7 @@ Abort(); } - if (mParseEndListener) { - mParseEndListener->SetIsStale(); - mParseEndListener = nullptr; - } + mParseEndListener = nullptr; MOZ_ASSERT(!mFlagSyncLooping, "we rather crash than hang"); mFlagSyncLooping = false; diff -Nru firefox-esr-140.9.0esr/dom/xhr/XMLHttpRequestMainThread.h firefox-esr-140.9.1esr/dom/xhr/XMLHttpRequestMainThread.h --- firefox-esr-140.9.0esr/dom/xhr/XMLHttpRequestMainThread.h 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/dom/xhr/XMLHttpRequestMainThread.h 2026-04-03 15:52:20.000000000 +0000 @@ -47,6 +47,7 @@ #include "mozilla/dom/XMLHttpRequestEventTarget.h" #include "mozilla/dom/XMLHttpRequestString.h" #include "mozilla/Encoding.h" +#include "mozilla/WeakPtr.h" #ifdef Status /* Xlib headers insist on this for some reason... Nuke it because @@ -183,6 +184,7 @@ // Make sure that any non-DOM interfaces added here are also added to // nsXMLHttpRequestXPCOMifier. class XMLHttpRequestMainThread final : public XMLHttpRequest, + public SupportsWeakPtr, public nsIStreamListener, public nsIChannelEventSink, public nsIProgressEventSink, @@ -844,21 +846,18 @@ public: NS_DECL_ISUPPORTS NS_IMETHOD HandleEvent(Event* event) override { - if (mXHR) { - mXHR->OnBodyParseEnd(); + if (RefPtr xhr = mXHR.get()) { + xhr->OnBodyParseEnd(); } - mXHR = nullptr; return NS_OK; } explicit nsXHRParseEndListener(XMLHttpRequestMainThread* aXHR) : mXHR(aXHR) {} - void SetIsStale() { mXHR = nullptr; } - private: virtual ~nsXHRParseEndListener() = default; - XMLHttpRequestMainThread* mXHR; + WeakPtr mXHR; }; } // namespace dom diff -Nru firefox-esr-140.9.0esr/gfx/layers/RemoteTextureMap.cpp firefox-esr-140.9.1esr/gfx/layers/RemoteTextureMap.cpp --- firefox-esr-140.9.0esr/gfx/layers/RemoteTextureMap.cpp 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/gfx/layers/RemoteTextureMap.cpp 2026-04-03 15:52:21.000000000 +0000 @@ -1305,7 +1305,7 @@ return false; } - auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); + owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); // When owner is alreay unregistered, remote texture will not be pushed. if (!owner || owner->mIsContextLost) { // This could happen with IPC abnormal shutdown diff -Nru firefox-esr-140.9.0esr/gfx/layers/wr/WebRenderBridgeParent.cpp firefox-esr-140.9.1esr/gfx/layers/wr/WebRenderBridgeParent.cpp --- firefox-esr-140.9.0esr/gfx/layers/wr/WebRenderBridgeParent.cpp 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/gfx/layers/wr/WebRenderBridgeParent.cpp 2026-04-03 15:52:21.000000000 +0000 @@ -477,8 +477,10 @@ wr::Vec mVec; void* Grow(void* aPtr, size_t aLength) { + // Only grow if capacity is insufficient. if (aLength > mVec.Capacity()) { - mVec.Reserve(aLength - mVec.Capacity()); + // Reserve() is relative to existing length. + mVec.Reserve(aLength - mVec.Length()); } return mVec.inner.data; } @@ -492,20 +494,17 @@ static bool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader, wr::TransactionBuilder& aUpdates) { - wr::Vec sourceBytes; - Maybe> ptr = - aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes); - if (ptr.isNothing()) { - gfxCriticalNote << "No read pointer from reader for sanitizing font " + wr::Vec source; + if (!aReader.Read(aOp.bytes(), source)) { + gfxCriticalNote << "Failed to read data for sanitizing font " << aOp.key().mHandle; return false; } - Range& source = ptr.ref(); // Attempt to sanitize the font before passing it along for updating. // Ensure that we're not strict here about font types, since any font that // failed generating a descriptor might end up here as raw font data. size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize( - source.begin().get(), source.length(), false); + source.Data(), source.Length(), false); if (!lengthHint) { gfxCriticalNote << "Could not determine font type for sanitizing font " << aOp.key().mHandle; @@ -513,7 +512,7 @@ } gfxOTSExpandingMemoryStream output(lengthHint); gfxOTSContext otsContext; - if (!otsContext.Process(&output, source.begin().get(), source.length())) { + if (!otsContext.Process(&output, source.Data(), source.Length())) { gfxCriticalNote << "Failed sanitizing font " << aOp.key().mHandle; return false; } diff -Nru firefox-esr-140.9.0esr/gfx/ots/src/cff.cc firefox-esr-140.9.1esr/gfx/ots/src/cff.cc --- firefox-esr-140.9.0esr/gfx/ots/src/cff.cc 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/gfx/ots/src/cff.cc 2026-04-03 15:52:21.000000000 +0000 @@ -556,7 +556,7 @@ return OTS_FAILURE(); } uint16_t k = out_cff->region_index_count.at(vsindex); - + if (operands.back().first > static_cast(0xffff) || operands.back().first < 0){ return OTS_FAILURE(); } @@ -1050,21 +1050,20 @@ if (operands.size() != 2) { return OTS_FAILURE(); } - if (operands.back().second != DICT_OPERAND_INTEGER) { + // We pass table.length() + 1 here because it's OK for private_offset to be equal to + // table.length(), provided private_length turns out to be zero. + if (!CheckOffset(operands.back(), table.length() + 1)) { return OTS_FAILURE(); } const int32_t private_offset = operands.back().first; operands.pop_back(); - if (operands.back().second != DICT_OPERAND_INTEGER) { + // The next operand is a length, not an offset, but we can usefully apply the same check: + // if it is negative or exceeds the table length, it cannot be valid. + if (!CheckOffset(operands.back(), table.length())) { return OTS_FAILURE(); } const int32_t private_length = operands.back().first; - if (private_offset > static_cast(table.length())) { - return OTS_FAILURE(); - } - if (private_length >= static_cast(table.length()) || private_length < 0) { - return OTS_FAILURE(); - } + // The offset & length were individually plausible; check that the combination doesn't overflow the table. if (private_length + private_offset > static_cast(table.length()) || private_length + private_offset < 0) { return OTS_FAILURE(); } diff -Nru firefox-esr-140.9.0esr/gfx/ots/src/colr.cc firefox-esr-140.9.1esr/gfx/ots/src/colr.cc --- firefox-esr-140.9.0esr/gfx/ots/src/colr.cc 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/gfx/ots/src/colr.cc 2026-04-03 15:52:21.000000000 +0000 @@ -788,9 +788,8 @@ } int32_t prevGlyphID = -1; - // We loop over the list twice, first to collect all the glyph IDs present, - // and then to check they can be parsed. - size_t saveOffset = subtable.offset(); + // We first collect all the glyph IDs present, and their paint offsets, + // then check they can all be parsed. for (auto i = 0u; i < numBaseGlyphPaintRecords; ++i) { uint16_t glyphID; uint32_t paintOffset; @@ -818,18 +817,9 @@ prevGlyphID = glyphID; } - subtable.set_offset(saveOffset); - for (auto i = 0u; i < numBaseGlyphPaintRecords; ++i) { - uint16_t glyphID; - uint32_t paintOffset; - - if (!subtable.ReadU16(&glyphID) || - !subtable.ReadU32(&paintOffset)) { - return OTS_FAILURE_MSG("Failed to read base glyph list"); - } - - if (!ParsePaint(font, data + paintOffset, length - paintOffset, state)) { - return OTS_FAILURE_MSG("Failed to parse paint for base glyph ID %u", glyphID); + for (const auto& [gid, rec] : state.baseGlyphMap) { + if (!ParsePaint(font, rec.first, rec.second, state)) { + return OTS_FAILURE_MSG("Failed to parse paint for base glyph ID %u", gid); } // After each base glyph record is fully processed, the visited set should be clear; diff -Nru firefox-esr-140.9.0esr/image/decoders/nsBMPDecoder.cpp firefox-esr-140.9.1esr/image/decoders/nsBMPDecoder.cpp --- firefox-esr-140.9.0esr/image/decoders/nsBMPDecoder.cpp 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/image/decoders/nsBMPDecoder.cpp 2026-04-03 15:52:21.000000000 +0000 @@ -238,7 +238,8 @@ nsBMPDecoder::~nsBMPDecoder() {} // Obtains the size of the compressed image resource. -int32_t nsBMPDecoder::GetCompressedImageSize() const { +uint32_t nsBMPDecoder::GetCompressedImageSize() const { + // Keep this in sync with the overflow check in ReadInfoHeaderRest. // In the RGB case mImageSize might not be set, so compute it manually. MOZ_ASSERT(mPixelRowSize != 0); return mH.mCompression == Compression::RGB ? mPixelRowSize * AbsoluteHeight() @@ -637,6 +638,16 @@ mPixelRowSize += 4 - surplus; } + if (mIsWithinICO && mH.mCompression == Compression::RGB) { + // The ICO decoders calls GetCompressedImageSize so we need to make sure the + // computation it does cannot overflow. Keep this in sync with that + // function. + auto product = CheckedInt(mPixelRowSize) * AbsoluteHeight(); + if (!product.isValid()) { + return Transition::TerminateFailure(); + } + } + size_t bitFieldsLengthStillToRead = 0; if (mH.mCompression == Compression::BITFIELDS) { // Need to read bitfields. diff -Nru firefox-esr-140.9.0esr/image/decoders/nsBMPDecoder.h firefox-esr-140.9.1esr/image/decoders/nsBMPDecoder.h --- firefox-esr-140.9.0esr/image/decoders/nsBMPDecoder.h 2026-03-17 09:42:11.000000000 +0000 +++ firefox-esr-140.9.1esr/image/decoders/nsBMPDecoder.h 2026-04-03 15:52:21.000000000 +0000 @@ -159,7 +159,7 @@ size_t GetImageDataLength() const { return mImageDataLength; } /// Obtains the size of the compressed image resource. - int32_t GetCompressedImageSize() const; + uint32_t GetCompressedImageSize() const; /// Mark this BMP as being within an ICO file. Only used for testing purposes /// because the ICO-specific constructor does this marking automatically. @@ -205,7 +205,7 @@ nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength, bool aForClipboard); - int32_t AbsoluteHeight() const { return abs(mH.mHeight); } + uint32_t AbsoluteHeight() const { return abs(mH.mHeight); } uint32_t* RowBuffer(); void ClearRowBufferRemainder(); diff -Nru firefox-esr-140.9.0esr/image/decoders/nsICODecoder.cpp firefox-esr-140.9.1esr/image/decoders/nsICODecoder.cpp --- firefox-esr-140.9.0esr/image/decoders/nsICODecoder.cpp 2026-03-17 09:42:10.000000000 +0000 +++ firefox-esr-140.9.1esr/image/decoders/nsICODecoder.cpp 2026-04-03 15:52:20.000000000 +0000 @@ -136,7 +136,7 @@ // The first resource starts right after the directory, which starts right // after the ICO header. - return ICOHEADERSIZE + mNumIcons * ICODIRENTRYSIZE; + return ICOHEADERSIZE + static_cast(mNumIcons) * ICODIRENTRYSIZE; } LexerTransition nsICODecoder::ReadDirEntry(const char* aData) { @@ -221,7 +221,11 @@ // Move to the resource data to start metadata decoding. mDirEntry = &mUnsizedDirEntries[0]; - size_t offsetToResource = mDirEntry->mImageOffset - FirstResourceOffset(); + // We ignored any dir entries whose offset didn't make sense before this. + MOZ_ASSERT(static_cast(mDirEntry->mImageOffset) >= + FirstResourceOffset()); + size_t offsetToResource = + static_cast(mDirEntry->mImageOffset) - FirstResourceOffset(); return Transition::ToUnbuffered(ICOState::FOUND_RESOURCE, ICOState::SKIP_TO_RESOURCE, offsetToResource); } @@ -316,6 +320,9 @@ mDownscaler.emplace(OutputSize().ToUnknownSize()); } + // We ignored any dir entries whose offset didn't make sense before this. + MOZ_ASSERT(static_cast(mDirEntry->mImageOffset) >= + FirstResourceOffset()); size_t offsetToResource = mDirEntry->mImageOffset - FirstResourceOffset(); return Transition::ToUnbuffered(ICOState::FOUND_RESOURCE, ICOState::SKIP_TO_RESOURCE, offsetToResource); @@ -437,37 +444,67 @@ // Do we have an AND mask on this BMP? If so, we need to read it after we read // the BMP data itself. - uint32_t bmpDataLength = bmpDecoder->GetCompressedImageSize() + 4 * numColors; - bool hasANDMask = (BITMAPINFOSIZE + bmpDataLength) < mDirEntry->mBytesInRes; + auto bmpDataLength = + CheckedInt(bmpDecoder->GetCompressedImageSize()) + + 4 * numColors; + auto fullBmpLength = bmpDataLength + BITMAPINFOSIZE; + if (!bmpDataLength.isValid() || !fullBmpLength.isValid() || + fullBmpLength.value() > mDirEntry->mBytesInRes) { + // Claimed data length inside the bmp resource exceeds dir entry size. + return Transition::TerminateFailure(); + } + bool hasANDMask = fullBmpLength.value() < mDirEntry->mBytesInRes; ICOState afterBMPState = hasANDMask ? ICOState::PREPARE_FOR_MASK : ICOState::FINISHED_RESOURCE; // Read in the rest of the BMP unbuffered. return Transition::ToUnbuffered(afterBMPState, ICOState::READ_RESOURCE, - bmpDataLength); + bmpDataLength.value()); } LexerTransition nsICODecoder::PrepareForMask() { MOZ_ASSERT(mDirEntry); - MOZ_ASSERT(mContainedDecoder->GetDecodeDone()); // We have received all of the data required by the BMP decoder so flushing - // here guarantees the decode has finished. + // here guarantees the decode has finished, if we have a valid file. if (!FlushContainedDecoder()) { return Transition::TerminateFailure(); } - MOZ_ASSERT(mContainedDecoder->GetDecodeDone()); + if (!mContainedDecoder->GetDecodeDone()) { + return Transition::TerminateFailure(); + } RefPtr bmpDecoder = static_cast(mContainedDecoder.get()); + if (!bmpDecoder->GetImageData() || bmpDecoder->GetImageDataLength() == 0) { + return Transition::TerminateFailure(); + } + if (mDownscaler) { + if (mDownscaler->TargetSize().width < 0 || + mDownscaler->TargetSize().height < 0 || + bmpDecoder->GetImageDataLength() != + static_cast(mDownscaler->TargetSize().width * + mDownscaler->TargetSize().height * 4)) { + return Transition::TerminateFailure(); + } + } else { + if (mDirEntry->mSize.width < 0 || mDirEntry->mSize.height < 0 || + bmpDecoder->GetImageDataLength() != + static_cast(mDirEntry->mSize.width * + mDirEntry->mSize.height * 4)) { + return Transition::TerminateFailure(); + } + } + uint16_t numColors = GetNumColors(); MOZ_ASSERT(numColors != uint16_t(-1)); // Determine the length of the AND mask. uint32_t bmpLengthWithHeader = BITMAPINFOSIZE + bmpDecoder->GetCompressedImageSize() + 4 * numColors; + // We can't get here unless this is true. MOZ_ASSERT(bmpLengthWithHeader < mDirEntry->mBytesInRes); uint32_t maskLength = mDirEntry->mBytesInRes - bmpLengthWithHeader; @@ -491,9 +528,6 @@ // produced, so we need to downscale the mask into a temporary buffer and then // combine the mask's alpha values with the color values from the image. if (mDownscaler) { - MOZ_ASSERT(bmpDecoder->GetImageDataLength() == - mDownscaler->TargetSize().width * - mDownscaler->TargetSize().height * sizeof(uint32_t)); mMaskBuffer = MakeUniqueFallible(bmpDecoder->GetImageDataLength()); if (NS_WARN_IF(!mMaskBuffer)) { @@ -616,7 +650,11 @@ return Transition::TerminateFailure(); } - MOZ_ASSERT(mContainedDecoder->GetDecodeDone()); + if (!mContainedDecoder->GetDecodeDone()) { + // We've sent as much data as the dir entry says for this resource, if it's + // not done by now then something is corrupt. + return Transition::TerminateFailure(); + } // If it is a metadata decode, all we were trying to get was the size // information missing from the dir entry. diff -Nru firefox-esr-140.9.0esr/js/src/builtin/temporal/Instant.cpp firefox-esr-140.9.1esr/js/src/builtin/temporal/Instant.cpp --- firefox-esr-140.9.0esr/js/src/builtin/temporal/Instant.cpp 2026-03-17 09:42:12.000000000 +0000 +++ firefox-esr-140.9.1esr/js/src/builtin/temporal/Instant.cpp 2026-04-03 15:52:22.000000000 +0000 @@ -235,10 +235,10 @@ if (!result) { return nullptr; } - if (y) { + if (length > 1) { result->setDigit(1, y); } - if (x) { + if (length > 0) { result->setDigit(0, x); } return result; diff -Nru firefox-esr-140.9.0esr/js/src/vm/StructuredClone.cpp firefox-esr-140.9.1esr/js/src/vm/StructuredClone.cpp --- firefox-esr-140.9.0esr/js/src/vm/StructuredClone.cpp 2026-03-17 09:42:14.000000000 +0000 +++ firefox-esr-140.9.1esr/js/src/vm/StructuredClone.cpp 2026-04-03 15:52:24.000000000 +0000 @@ -1582,6 +1582,7 @@ Rooted memoryObj(context(), &obj->unwrapAs()); + JSAutoRealm ar(context(), memoryObj); Rooted sab( context(), &memoryObj->buffer().as()); diff -Nru firefox-esr-140.9.0esr/layout/generic/ScrollContainerFrame.cpp firefox-esr-140.9.1esr/layout/generic/ScrollContainerFrame.cpp --- firefox-esr-140.9.0esr/layout/generic/ScrollContainerFrame.cpp 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/generic/ScrollContainerFrame.cpp 2026-04-03 15:52:25.000000000 +0000 @@ -2457,9 +2457,12 @@ if (aParams.IsInstant()) { // Asynchronous scrolling is not allowed, so we'll kill any existing // async-scrolling process and do an instant scroll. + AutoWeakFrame weakFrame(this); CompleteAsyncScroll(GetScrollPosition(), range, std::move(snapTargetIds), aParams.mOrigin); - mApzSmoothScrollDestination = Nothing(); + if (weakFrame.IsAlive()) { + mApzSmoothScrollDestination = Nothing(); + } return; } diff -Nru firefox-esr-140.9.0esr/layout/style/FontFace.cpp firefox-esr-140.9.1esr/layout/style/FontFace.cpp --- firefox-esr-140.9.0esr/layout/style/FontFace.cpp 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/style/FontFace.cpp 2026-04-03 15:52:25.000000000 +0000 @@ -254,6 +254,7 @@ } mImpl->Load(aRv); + mImpl->UpdateOwnerKeepAlive(); return mLoaded; } @@ -265,40 +266,27 @@ return nullptr; } + if (mImpl) { + mImpl->UpdateOwnerKeepAlive(); + } + return mLoaded; } void FontFace::MaybeResolve() { gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); + MOZ_ASSERT(!NS_IsMainThread() || nsContentUtils::IsSafeToRunScript()); + MOZ_ASSERT(!gfxFontUtils::CurrentServoStyleSet()); - if (!mLoaded) { - return; - } - - if (ServoStyleSet* ss = gfxFontUtils::CurrentServoStyleSet()) { - // See comments in Gecko_GetFontMetrics. - ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this)); - return; + if (RefPtr loaded = mLoaded) { + loaded->MaybeResolve(this); } - - if (NS_IsMainThread() && !nsContentUtils::IsSafeToRunScript()) { - nsContentUtils::AddScriptRunner(NewRunnableMethod( - "FontFace::MaybeResolve", this, &FontFace::MaybeResolve)); - return; - } - - mLoaded->MaybeResolve(this); } void FontFace::MaybeReject(nsresult aResult) { gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); - - if (ServoStyleSet* ss = gfxFontUtils::CurrentServoStyleSet()) { - // See comments in Gecko_GetFontMetrics. - ss->AppendTask( - PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult)); - return; - } + MOZ_ASSERT(!NS_IsMainThread() || nsContentUtils::IsSafeToRunScript()); + MOZ_ASSERT(!gfxFontUtils::CurrentServoStyleSet()); if (mLoaded) { mLoaded->MaybeReject(aResult); diff -Nru firefox-esr-140.9.0esr/layout/style/FontFaceImpl.cpp firefox-esr-140.9.1esr/layout/style/FontFaceImpl.cpp --- firefox-esr-140.9.0esr/layout/style/FontFaceImpl.cpp 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/style/FontFaceImpl.cpp 2026-04-03 15:52:26.000000000 +0000 @@ -385,35 +385,45 @@ } void FontFaceImpl::UpdateOwnerPromise() { - if (!mFontFaceSet->IsOnOwningThread()) { - mFontFaceSet->DispatchToOwningThread( - "FontFaceImpl::UpdateOwnerPromise", - [self = RefPtr{this}] { self->UpdateOwnerPromise(); }); + mFontFaceSet->DispatchToOwningThread( + "FontFaceImpl::UpdateOwnerPromise", + [self = RefPtr{this}] { self->UpdateOwnerPromiseSync(); }); +} + +void FontFaceImpl::UpdateOwnerKeepAlive() { + AssertIsOnOwningThread(); + if (!mOwner) { + MOZ_DIAGNOSTIC_ASSERT(!mKeepingOwnerAlive); return; } + const bool shouldKeepOwnerAlive = + mStatus == FontFaceLoadStatus::Loading && !!mOwner->GetParentObject(); + if (shouldKeepOwnerAlive == mKeepingOwnerAlive) { + return; + } + mKeepingOwnerAlive = shouldKeepOwnerAlive; + if (shouldKeepOwnerAlive) { + mOwner->AddRef(); + } else { + mOwner->Release(); + } +} +void FontFaceImpl::UpdateOwnerPromiseSync() { if (NS_WARN_IF(!mOwner)) { MOZ_DIAGNOSTIC_ASSERT(!mKeepingOwnerAlive); return; } + RefPtr owner = mOwner; + UpdateOwnerKeepAlive(); if (mStatus == FontFaceLoadStatus::Loaded) { - mOwner->MaybeResolve(); + owner->MaybeResolve(); } else if (mStatus == FontFaceLoadStatus::Error) { if (mSourceType == eSourceType_Buffer) { - mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR); - } else { - mOwner->MaybeReject(NS_ERROR_DOM_NETWORK_ERR); - } - } - - const bool shouldKeepOwnerAlive = mStatus == FontFaceLoadStatus::Loading; - if (shouldKeepOwnerAlive != mKeepingOwnerAlive) { - mKeepingOwnerAlive = shouldKeepOwnerAlive; - if (shouldKeepOwnerAlive) { - mOwner->AddRef(); + owner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR); } else { - mOwner->Release(); + owner->MaybeReject(NS_ERROR_DOM_NETWORK_ERR); } } } diff -Nru firefox-esr-140.9.0esr/layout/style/FontFaceImpl.h firefox-esr-140.9.1esr/layout/style/FontFaceImpl.h --- firefox-esr-140.9.0esr/layout/style/FontFaceImpl.h 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/style/FontFaceImpl.h 2026-04-03 15:52:25.000000000 +0000 @@ -202,6 +202,8 @@ void InitializeSourceURL(const nsACString& aURL); void InitializeSourceBuffer(uint8_t* aBuffer, uint32_t aLength); + void UpdateOwnerKeepAlive(); + /** * Sets all of the descriptor values in mDescriptors using values passed * to the JS constructor. @@ -221,6 +223,7 @@ // Helper function for Load. void DoLoad(); void UpdateOwnerPromise(); + void UpdateOwnerPromiseSync(); // Helper function for the descriptor setter methods. // Returns true if the descriptor was modified, false if descriptor is diff -Nru firefox-esr-140.9.0esr/layout/style/FontFaceSetImpl.cpp firefox-esr-140.9.1esr/layout/style/FontFaceSetImpl.cpp --- firefox-esr-140.9.0esr/layout/style/FontFaceSetImpl.cpp 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/style/FontFaceSetImpl.cpp 2026-04-03 15:52:26.000000000 +0000 @@ -764,21 +764,6 @@ } void FontFaceSetImpl::DispatchCheckLoadingFinishedAfterDelay() { - gfxFontUtils::AssertSafeThreadOrServoFontMetricsLocked(); - - if (ServoStyleSet* set = gfxFontUtils::CurrentServoStyleSet()) { - // See comments in Gecko_GetFontMetrics. - // - // We can't just dispatch the runnable below if we're not on the main - // thread, since it needs to take a strong reference to the FontFaceSet, - // and being a DOM object, FontFaceSet doesn't support thread-safe - // refcounting. - set->AppendTask( - PostTraversalTask::DispatchFontFaceSetCheckLoadingFinishedAfterDelay( - this)); - return; - } - DispatchToOwningThread( "FontFaceSetImpl::DispatchCheckLoadingFinishedAfterDelay", [self = RefPtr{this}]() { self->CheckLoadingFinishedAfterDelay(); }); diff -Nru firefox-esr-140.9.0esr/layout/style/PostTraversalTask.cpp firefox-esr-140.9.1esr/layout/style/PostTraversalTask.cpp --- firefox-esr-140.9.0esr/layout/style/PostTraversalTask.cpp 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/style/PostTraversalTask.cpp 2026-04-03 15:52:26.000000000 +0000 @@ -20,24 +20,11 @@ void PostTraversalTask::Run() { switch (mType) { - case Type::ResolveFontFaceLoadedPromise: - static_cast(mTarget)->MaybeResolve(); - break; - - case Type::RejectFontFaceLoadedPromise: - static_cast(mTarget)->MaybeReject(mResult); - break; - case Type::DispatchLoadingEventAndReplaceReadyPromise: static_cast(mTarget) ->DispatchLoadingEventAndReplaceReadyPromise(); break; - case Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay: - static_cast(mTarget) - ->DispatchCheckLoadingFinishedAfterDelay(); - break; - case Type::LoadFontEntry: static_cast(mTarget)->ContinueLoad(); break; diff -Nru firefox-esr-140.9.0esr/layout/style/PostTraversalTask.h firefox-esr-140.9.1esr/layout/style/PostTraversalTask.h --- firefox-esr-140.9.0esr/layout/style/PostTraversalTask.h 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/style/PostTraversalTask.h 2026-04-03 15:52:25.000000000 +0000 @@ -14,7 +14,6 @@ namespace mozilla { class ServoStyleSet; namespace dom { -class FontFace; class FontFaceSet; class FontFaceSetImpl; } // namespace dom @@ -36,21 +35,6 @@ */ class PostTraversalTask { public: - static PostTraversalTask ResolveFontFaceLoadedPromise( - dom::FontFace* aFontFace) { - auto task = PostTraversalTask(Type::ResolveFontFaceLoadedPromise); - task.mTarget = aFontFace; - return task; - } - - static PostTraversalTask RejectFontFaceLoadedPromise(dom::FontFace* aFontFace, - nsresult aResult) { - auto task = PostTraversalTask(Type::ResolveFontFaceLoadedPromise); - task.mTarget = aFontFace; - task.mResult = aResult; - return task; - } - static PostTraversalTask DispatchLoadingEventAndReplaceReadyPromise( dom::FontFaceSet* aFontFaceSet) { auto task = @@ -59,14 +43,6 @@ return task; } - static PostTraversalTask DispatchFontFaceSetCheckLoadingFinishedAfterDelay( - dom::FontFaceSetImpl* aFontFaceSet) { - auto task = PostTraversalTask( - Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay); - task.mTarget = aFontFaceSet; - return task; - } - static PostTraversalTask LoadFontEntry(gfxUserFontEntry* aFontEntry) { auto task = PostTraversalTask(Type::LoadFontEntry); task.mTarget = aFontEntry; @@ -92,19 +68,9 @@ // please add an assertion that class' destructor that we are not in a Servo // traversal, to protect against the possibility of having dangling pointers. enum class Type { - // mTarget (FontFace*) - ResolveFontFaceLoadedPromise, - - // mTarget (FontFace*) - // mResult - RejectFontFaceLoadedPromise, - // mTarget (FontFaceSet*) DispatchLoadingEventAndReplaceReadyPromise, - // mTarget (FontFaceSetImpl*) - DispatchFontFaceSetCheckLoadingFinishedAfterDelay, - // mTarget (gfxUserFontEntry*) LoadFontEntry, @@ -115,12 +81,10 @@ FontInfoUpdate, }; - explicit PostTraversalTask(Type aType) - : mType(aType), mTarget(nullptr), mResult(NS_OK) {} + explicit PostTraversalTask(Type aType) : mType(aType), mTarget(nullptr) {} - Type mType; - void* mTarget; - nsresult mResult; + const Type mType; + void* mTarget = nullptr; }; } // namespace mozilla diff -Nru firefox-esr-140.9.0esr/layout/tables/celldata.h firefox-esr-140.9.1esr/layout/tables/celldata.h --- firefox-esr-140.9.0esr/layout/tables/celldata.h 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/tables/celldata.h 2026-04-03 15:52:26.000000000 +0000 @@ -10,6 +10,7 @@ #include "nsCoord.h" #include "mozilla/gfx/Types.h" #include "mozilla/WritingModes.h" +#include #include class nsTableCellFrame; @@ -292,6 +293,10 @@ } inline void CellData::SetRowSpanOffset(uint32_t aSpan) { + MOZ_ASSERT(aSpan > 0, "a zero-sized span is nonsensical"); + MOZ_ASSERT(aSpan <= MAX_ROWSPAN, "span shouldn't exceed what we can handle"); + aSpan = std::min(aSpan, static_cast(MAX_ROWSPAN)); + mBits &= ~ROW_SPAN_OFFSET; mBits |= (aSpan << ROW_SPAN_SHIFT); mBits |= SPAN; @@ -310,6 +315,10 @@ } inline void CellData::SetColSpanOffset(uint32_t aSpan) { + MOZ_ASSERT(aSpan > 0, "a zero-sized span is nonsensical"); + MOZ_ASSERT(aSpan <= MAX_COLSPAN, "span shouldn't exceed what we can handle"); + aSpan = std::min(aSpan, static_cast(MAX_COLSPAN)); + mBits &= ~COL_SPAN_OFFSET; mBits |= (aSpan << COL_SPAN_SHIFT); diff -Nru firefox-esr-140.9.0esr/layout/tables/nsCellMap.cpp firefox-esr-140.9.1esr/layout/tables/nsCellMap.cpp --- firefox-esr-140.9.0esr/layout/tables/nsCellMap.cpp 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/layout/tables/nsCellMap.cpp 2026-04-03 15:52:26.000000000 +0000 @@ -1845,7 +1845,9 @@ break; } } - return colSpan; + + // Enforce that the effective colSpan is between 1 and MAX_COLSPAN: + return std::clamp(colSpan, 1, MAX_COLSPAN); } int32_t nsCellMap::GetRowSpanForNewCell(nsTableCellFrame* aCellFrameToAdd, @@ -1856,7 +1858,7 @@ if (0 == rowSpan) { // Use a min value of 2 for a zero rowspan to make computations easier // elsewhere. Zero rowspans are only content dependent! - rowSpan = std::max(2, mContentRowCount - aRowIndex); + rowSpan = std::clamp(mContentRowCount - aRowIndex, 2, MAX_ROWSPAN); aIsZeroRowSpan = true; } return rowSpan; @@ -1910,7 +1912,9 @@ break; } } - return rowSpan; + + // Enforce that the effective rowSpan is between 1 and MAX_ROWSPAN: + return std::clamp(rowSpan, 1, MAX_ROWSPAN); } void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap, diff -Nru firefox-esr-140.9.0esr/media/libpng/ANNOUNCE firefox-esr-140.9.1esr/media/libpng/ANNOUNCE --- firefox-esr-140.9.0esr/media/libpng/ANNOUNCE 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/ANNOUNCE 2026-04-03 15:52:26.000000000 +0000 @@ -1,5 +1,5 @@ -libpng 1.6.55 - February 9, 2026 -================================ +libpng 1.6.56 - March 25, 2026 +============================== This is a public release of libpng, intended for use in production code. @@ -9,10 +9,10 @@ Source files: - * libpng-1.6.55.tar.xz (LZMA-compressed, recommended) - * libpng-1.6.55.tar.gz (deflate-compressed) - * lpng1655.7z (LZMA-compressed) - * lpng1655.zip (deflate-compressed) + * libpng-1.6.56.tar.xz (LZMA-compressed, recommended) + * libpng-1.6.56.tar.gz (deflate-compressed) + * lpng1656.7z (LZMA-compressed) + * lpng1656.zip (deflate-compressed) Other information: @@ -22,14 +22,39 @@ * TRADEMARK.md -Changes from version 1.6.54 to version 1.6.55 +Changes from version 1.6.55 to version 1.6.56 --------------------------------------------- - * Fixed CVE-2026-25646 (high severity): - Heap buffer overflow in `png_set_quantize`. - (Reported and fixed by Joshua Inscoe.) - * Resolved an oss-fuzz build issue involving nalloc. - (Contributed by Philippe Antoine.) + * Fixed CVE-2026-33416 (high severity): + Use-after-free via pointer aliasing in `png_set_tRNS` and `png_set_PLTE`. + (Reported by Halil Oktay and Ryo Shimada; + fixed by Halil Oktay and Cosmin Truta.) + * Fixed CVE-2026-33636 (high severity): + Out-of-bounds read/write in the palette expansion on ARM Neon. + (Reported by Taegu Ha; fixed by Taegu Ha and Cosmin Truta.) + * Fixed uninitialized reads beyond `num_trans` in `trans_alpha` buffers. + (Contributed by Halil Oktay.) + * Fixed stale `info_ptr->palette` after in-place gamma and background + transforms. + * Fixed wrong channel indices in `png_image_read_and_map` RGB_ALPHA path. + (Contributed by Yuelin Wang.) + * Fixed wrong background color in colormap read. + (Contributed by Yuelin Wang.) + * Fixed dead loop in sPLT write. + (Contributed by Yuelin Wang.) + * Added missing null pointer checks in four public API functions. + (Contributed by Yuelin Wang.) + * Validated shift bit depths in `png_set_shift` to prevent infinite loop. + (Contributed by Yuelin Wang.) + * Avoided undefined behavior in library and tests. + * Deprecated the hardly-ever-tested POINTER_INDEXING config option. + * Added negative-stride test coverage for the simplified API. + * Fixed memory leaks and API misuse in oss-fuzz. + (Contributed by Owen Sanzas.) + * Implemented various fixes and improvements in oss-fuzz. + (Contributed by Bob Friesenhahn and Philippe Antoine.) + * Performed various refactorings and cleanups. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net. Subscription is required; visit diff -Nru firefox-esr-140.9.0esr/media/libpng/AUTHORS firefox-esr-140.9.1esr/media/libpng/AUTHORS --- firefox-esr-140.9.0esr/media/libpng/AUTHORS 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/AUTHORS 2026-04-03 15:52:25.000000000 +0000 @@ -15,6 +15,7 @@ * Glenn Randers-Pehrson * Greg Roelofs * Guy Eric Schalnat + * Halil Oktay * James Yu * John Bowler * Joshua Inscoe @@ -34,12 +35,14 @@ * Sam Bushell * Samuel Williams * Simon-Pierre Cadieux + * Taegu Ha (하태구) * Tim Wegner * Tobias Stoeckmann * Tom Lane * Tom Tanner * Vadim Barkov * Willem van Schaik + * Yuelin Wang (王跃林) * Zhijie Liang * Apple Inc. - Zixu Wang (王子旭) diff -Nru firefox-esr-140.9.0esr/media/libpng/CHANGES firefox-esr-140.9.1esr/media/libpng/CHANGES --- firefox-esr-140.9.0esr/media/libpng/CHANGES 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/CHANGES 2026-04-03 15:52:25.000000000 +0000 @@ -6337,6 +6337,37 @@ Resolved an oss-fuzz build issue involving nalloc. (Contributed by Philippe Antoine.) +Version 1.6.56 [March 25, 2026] + Fixed CVE-2026-33416 (high severity): + Use-after-free via pointer aliasing in `png_set_tRNS` and `png_set_PLTE`. + (Reported by Halil Oktay and Ryo Shimada; + fixed by Halil Oktay and Cosmin Truta.) + Fixed CVE-2026-33636 (high severity): + Out-of-bounds read/write in the palette expansion on ARM Neon. + (Reported by Taegu Ha; fixed by Taegu Ha and Cosmin Truta.) + Fixed uninitialized reads beyond `num_trans` in `trans_alpha` buffers. + (Contributed by Halil Oktay.) + Fixed stale `info_ptr->palette` after in-place gamma and background + transforms. + Fixed wrong channel indices in `png_image_read_and_map` RGB_ALPHA path. + (Contributed by Yuelin Wang.) + Fixed wrong background color in colormap read. + (Contributed by Yuelin Wang.) + Fixed dead loop in sPLT write. + (Contributed by Yuelin Wang.) + Added missing null pointer checks in four public API functions. + (Contributed by Yuelin Wang.) + Validated shift bit depths in `png_set_shift` to prevent infinite loop. + (Contributed by Yuelin Wang.) + Avoided undefined behavior in library and tests. + Deprecated the hardly-ever-tested POINTER_INDEXING config option. + Added negative-stride test coverage for the simplified API. + Fixed memory leaks and API misuse in oss-fuzz. + (Contributed by Owen Sanzas.) + Implemented various fixes and improvements in oss-fuzz. + (Contributed by Bob Friesenhahn and Philippe Antoine.) + Performed various refactorings and cleanups. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net. Subscription is required; visit diff -Nru firefox-esr-140.9.0esr/media/libpng/README firefox-esr-140.9.1esr/media/libpng/README --- firefox-esr-140.9.0esr/media/libpng/README 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/README 2026-04-03 15:52:25.000000000 +0000 @@ -1,4 +1,4 @@ -README for libpng version 1.6.55 +README for libpng version 1.6.56 ================================ See the note about version numbers near the top of `png.h`. diff -Nru firefox-esr-140.9.0esr/media/libpng/arm/palette_neon_intrinsics.c firefox-esr-140.9.1esr/media/libpng/arm/palette_neon_intrinsics.c --- firefox-esr-140.9.0esr/media/libpng/arm/palette_neon_intrinsics.c 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/arm/palette_neon_intrinsics.c 2026-04-03 15:52:26.000000000 +0000 @@ -1,6 +1,6 @@ /* palette_neon_intrinsics.c - NEON optimised palette expansion functions * - * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 2017-2018 Arm Holdings. All rights reserved. * Written by Richard Townsend , February 2017. * @@ -48,12 +48,12 @@ w.val[0] = v.val[0]; w.val[1] = v.val[1]; w.val[2] = v.val[2]; - vst4q_u8(riffled_palette + (i << 2), w); + vst4q_u8(riffled_palette + i * 4, w); } /* Fix up the missing transparency values. */ for (i = 0; i < num_trans; i++) - riffled_palette[(i << 2) + 3] = trans_alpha[i]; + riffled_palette[i * 4 + 3] = trans_alpha[i]; } /* Expands a palettized row into RGBA8. */ @@ -77,27 +77,26 @@ * The NEON part writes forward from a given position, so we have * to seek this back by 4 pixels x 4 bytes. */ - *ddp = *ddp - ((pixels_per_chunk * sizeof(png_uint_32)) - 1); + *ddp = *ddp - (pixels_per_chunk * 4 - 1); - for (i = 0; i < row_width; i += pixels_per_chunk) + for (i = 0; i + pixels_per_chunk <= row_width; i += pixels_per_chunk) { uint32x4_t cur; - png_bytep sp = *ssp - i, dp = *ddp - (i << 2); + png_bytep sp = *ssp - i, dp = *ddp - i * 4; cur = vld1q_dup_u32 (riffled_palette + *(sp - 3)); cur = vld1q_lane_u32(riffled_palette + *(sp - 2), cur, 1); cur = vld1q_lane_u32(riffled_palette + *(sp - 1), cur, 2); cur = vld1q_lane_u32(riffled_palette + *(sp - 0), cur, 3); vst1q_u32((void *)dp, cur); } - if (i != row_width) - { - /* Remove the amount that wasn't processed. */ - i -= pixels_per_chunk; - } - /* Decrement output pointers. */ + /* Undo the pre-adjustment of *ddp before the pointer handoff, + * so the scalar fallback in pngrtran.c receives a dp that points + * to the correct position. + */ + *ddp = *ddp + (pixels_per_chunk * 4 - 1); *ssp = *ssp - i; - *ddp = *ddp - (i << 2); + *ddp = *ddp - i * 4; return i; } @@ -118,32 +117,30 @@ return 0; /* Seeking this back by 8 pixels x 3 bytes. */ - *ddp = *ddp - ((pixels_per_chunk * sizeof(png_color)) - 1); + *ddp = *ddp - (pixels_per_chunk * 3 - 1); - for (i = 0; i < row_width; i += pixels_per_chunk) + for (i = 0; i + pixels_per_chunk <= row_width; i += pixels_per_chunk) { uint8x8x3_t cur; - png_bytep sp = *ssp - i, dp = *ddp - ((i << 1) + i); - cur = vld3_dup_u8(palette + sizeof(png_color) * (*(sp - 7))); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 6)), cur, 1); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 5)), cur, 2); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 4)), cur, 3); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 3)), cur, 4); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 2)), cur, 5); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 1)), cur, 6); - cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 0)), cur, 7); + png_bytep sp = *ssp - i, dp = *ddp - i * 3; + cur = vld3_dup_u8(palette + *(sp - 7) * 3); + cur = vld3_lane_u8(palette + *(sp - 6) * 3, cur, 1); + cur = vld3_lane_u8(palette + *(sp - 5) * 3, cur, 2); + cur = vld3_lane_u8(palette + *(sp - 4) * 3, cur, 3); + cur = vld3_lane_u8(palette + *(sp - 3) * 3, cur, 4); + cur = vld3_lane_u8(palette + *(sp - 2) * 3, cur, 5); + cur = vld3_lane_u8(palette + *(sp - 1) * 3, cur, 6); + cur = vld3_lane_u8(palette + *(sp - 0) * 3, cur, 7); vst3_u8((void *)dp, cur); } - if (i != row_width) - { - /* Remove the amount that wasn't processed. */ - i -= pixels_per_chunk; - } - - /* Decrement output pointers. */ + /* Undo the pre-adjustment of *ddp before the pointer handoff, + * so the scalar fallback in pngrtran.c receives a dp that points + * to the correct position. + */ + *ddp = *ddp + (pixels_per_chunk * 3 - 1); *ssp = *ssp - i; - *ddp = *ddp - ((i << 1) + i); + *ddp = *ddp - i * 3; return i; } diff -Nru firefox-esr-140.9.0esr/media/libpng/libpng-manual.txt firefox-esr-140.9.1esr/media/libpng/libpng-manual.txt --- firefox-esr-140.9.0esr/media/libpng/libpng-manual.txt 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/libpng-manual.txt 2026-04-03 15:52:25.000000000 +0000 @@ -9,7 +9,7 @@ Based on: - libpng version 1.6.36, December 2018, through 1.6.55 - February 2026 + libpng version 1.6.36, December 2018, through 1.6.56 - March 2026 Updated and distributed by Cosmin Truta Copyright (c) 2018-2026 Cosmin Truta @@ -2318,7 +2318,7 @@ png_uint_32 height = PNG_PASS_ROWS(image_height, pass_number); Respectively these tell you the width and height of the sub-image -corresponding to the numbered pass. 'pass' is in in the range 0 to 6 - +corresponding to the numbered pass. 'pass' is in the range 0 to 6 - this can be confusing because the specification refers to the same passes as 1 to 7! Be careful, you must check both the width and height before calling png_read_rows() and not call it for that pass if either is zero. @@ -2457,7 +2457,7 @@ This function may be safely called when the relevant storage has already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. +by the user and not by libpng, and will in those cases do nothing. The "seq" parameter is ignored if only one item of the selected data type, such as PLTE, is allowed. If "seq" is not -1, and multiple items are allowed for the data type identified in the mask, such as text or @@ -3292,7 +3292,7 @@ don't have to wait for the disclaimer to go over the modem before they start seeing the image. Finally, keywords should be full words, not abbreviations. Keywords and text are in the ISO 8859-1 -(Latin-1) character set (a superset of regular ASCII) and can not +(Latin-1) character set (a superset of regular ASCII) and cannot contain NUL characters, and should not contain control or other unprintable characters. To make the comments widely readable, stick with basic ASCII, and avoid machine specific character set extensions @@ -3694,7 +3694,7 @@ This function may be safely called when the relevant storage has already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. +by the user and not by libpng, and will in those cases do nothing. The "seq" parameter is ignored if only one item of the selected data type, such as PLTE, is allowed. If "seq" is not -1, and multiple items are allowed for the data type identified in the mask, such as text or diff -Nru firefox-esr-140.9.0esr/media/libpng/moz.yaml firefox-esr-140.9.1esr/media/libpng/moz.yaml --- firefox-esr-140.9.0esr/media/libpng/moz.yaml 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/moz.yaml 2026-04-03 15:52:26.000000000 +0000 @@ -11,8 +11,9 @@ url: "http://www.libpng.org/pub/png/libpng.html" license: libpng - release: v1.6.55 (2026-02-09T22:02:20+02:00). - revision: v1.6.55 + release: v1.6.56 (2026-03-25T22:47:06+02:00). + + revision: v1.6.56 license-file: LICENSE diff -Nru firefox-esr-140.9.0esr/media/libpng/png.c firefox-esr-140.9.1esr/media/libpng/png.c --- firefox-esr-140.9.0esr/media/libpng/png.c 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/png.c 2026-04-03 15:52:26.000000000 +0000 @@ -13,7 +13,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_55 Your_png_h_is_not_version_1_6_55; +typedef png_libpng_version_1_6_56 Your_png_h_is_not_version_1_6_56; /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the * corresponding macro definitions. This causes a compile time failure if @@ -820,7 +820,7 @@ return PNG_STRING_COPYRIGHT #else return PNG_STRING_NEWLINE \ - "libpng version 1.6.55" PNG_STRING_NEWLINE \ + "libpng version 1.6.56" PNG_STRING_NEWLINE \ "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ @@ -1170,7 +1170,7 @@ return 1; /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so - * the fillowing calculates (X+Y+Z) of the reference white (media white, + * the following calculates (X+Y+Z) of the reference white (media white, * encoding white) itself: */ d = dblue; @@ -1215,9 +1215,9 @@ * (-0.0770) because the PNG spec itself requires the xy values to be * unsigned. whitey is also required to be 5 or more to avoid overflow. * - * Instead the upper limits have been relaxed to accomodate ACES AP1 where + * Instead the upper limits have been relaxed to accommodate ACES AP1 where * redz ends up as -600 (-0.006). ProPhotoRGB was already "in range." - * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy. + * The new limit accommodates the AP0 and AP1 ranges for z but not AP0 redy. */ const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10); if (xy->redx < 0 || xy->redx > fpLimit) return 1; @@ -1328,7 +1328,7 @@ * red-scale + green-scale + blue-scale = 1/white-y = white-scale * * So now we have a Cramer's rule solution where the determinants are just - * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * 3x3 - far more tractable. Unfortunately 3x3 determinants still involve * multiplication of three coefficients so we can't guarantee to avoid * overflow in the libpng fixed point representation. Using Cramer's rule in * floating point is probably a good choice here, but it's not an option for @@ -1697,7 +1697,7 @@ * into R, G and B channels. * * Previously it was suggested that an RGB profile on grayscale data could be - * handled. However it it is clear that using an RGB profile in this context + * handled. However it is clear that using an RGB profile in this context * must be an error - there is no specification of what it means. Thus it is * almost certainly more correct to ignore the profile. */ @@ -2915,7 +2915,7 @@ * * 2.2/(2+51/256) == 1.00035524 * - * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/- + * I.e. vanishingly small (<4E-4) but still detectable in 16-bit linear (+/- * 23). Note that the Adobe choice seems to be something intended to give an * exact number with 8 binary fractional digits - it is the closest to 2.2 * that is possible a base 2 .8p representation. diff -Nru firefox-esr-140.9.0esr/media/libpng/png.h firefox-esr-140.9.1esr/media/libpng/png.h --- firefox-esr-140.9.0esr/media/libpng/png.h 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/png.h 2026-04-03 15:52:26.000000000 +0000 @@ -1,6 +1,6 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.55 + * libpng version 1.6.56 * * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson @@ -14,7 +14,7 @@ * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.35, July 2018: * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.55, February 2026: + * libpng versions 1.6.36, December 2018, through 1.6.56, March 2026: * Cosmin Truta * See also "Contributing Authors", below. */ @@ -238,7 +238,7 @@ * ... * 1.5.30 15 10530 15.so.15.30[.0] * ... - * 1.6.55 16 10655 16.so.16.55[.0] + * 1.6.56 16 10656 16.so.16.56[.0] * * Henceforth the source version will match the shared-library major and * minor numbers; the shared-library major version number will be used for @@ -274,7 +274,7 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.55" +#define PNG_LIBPNG_VER_STRING "1.6.56" #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n" /* The versions of shared library builds should stay in sync, going forward */ @@ -285,7 +285,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 55 +#define PNG_LIBPNG_VER_RELEASE 56 /* This should be zero for a public release, or non-zero for a * development version. @@ -316,7 +316,7 @@ * From version 1.0.1 it is: * XXYYZZ, where XX=major, YY=minor, ZZ=release */ -#define PNG_LIBPNG_VER 10655 /* 1.6.55 */ +#define PNG_LIBPNG_VER 10656 /* 1.6.56 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -441,7 +441,7 @@ /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char *png_libpng_version_1_6_55; +typedef char *png_libpng_version_1_6_56; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -2360,7 +2360,7 @@ #endif /* Note while png_set_text() will accept a structure whose text, - * language, and translated keywords are NULL pointers, the structure + * language, and translated keywords are NULL pointers, the structure * returned by png_get_text will always contain regular * zero-terminated C strings. They might be empty strings but * they will never be NULL pointers. diff -Nru firefox-esr-140.9.0esr/media/libpng/pngconf.h firefox-esr-140.9.1esr/media/libpng/pngconf.h --- firefox-esr-140.9.0esr/media/libpng/pngconf.h 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngconf.h 2026-04-03 15:52:26.000000000 +0000 @@ -1,6 +1,6 @@ /* pngconf.h - machine-configurable file for libpng * - * libpng version 1.6.55 + * libpng version 1.6.56 * * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson diff -Nru firefox-esr-140.9.0esr/media/libpng/pngpriv.h firefox-esr-140.9.1esr/media/libpng/pngpriv.h --- firefox-esr-140.9.0esr/media/libpng/pngpriv.h 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngpriv.h 2026-04-03 15:52:26.000000000 +0000 @@ -971,7 +971,7 @@ * * At present these index values are not exported (not part of the public API) * so can be changed at will. For convenience the names are in lexical sort - * order but with the critical chunks at the start in the order of occurence in + * order but with the critical chunks at the start in the order of occurrence in * a PNG. * * PNG_INFO_ values do not exist for every one of these chunk handles; for @@ -2143,7 +2143,7 @@ * not valid it will be the index of a character in the supposed number. * * The format of a number is defined in the PNG extensions specification - * and this API is strictly conformant to that spec, not anyone elses! + * and this API is strictly conformant to that spec, not anyone else's! * * The format as a regular expression is: * diff -Nru firefox-esr-140.9.0esr/media/libpng/pngread.c firefox-esr-140.9.1esr/media/libpng/pngread.c --- firefox-esr-140.9.0esr/media/libpng/pngread.c 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngread.c 2026-04-03 15:52:26.000000000 +0000 @@ -771,7 +771,7 @@ png_read_finish_IDAT(png_ptr); #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Report invalid palette index; added at libng-1.5.10 */ + /* Report invalid palette index; added at libpng-1.5.10 */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_palette_max >= png_ptr->num_palette) png_benign_error(png_ptr, "Read palette index exceeding num_palette"); @@ -859,21 +859,19 @@ png_ptr->quantize_index = NULL; #endif - if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) - { - png_zfree(png_ptr, png_ptr->palette); - png_ptr->palette = NULL; - } - png_ptr->free_me &= ~PNG_FREE_PLTE; + /* png_ptr->palette is always independently allocated (not aliased + * with info_ptr->palette), so free it unconditionally. + */ + png_free(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; #if defined(PNG_tRNS_SUPPORTED) || \ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) - { - png_free(png_ptr, png_ptr->trans_alpha); - png_ptr->trans_alpha = NULL; - } - png_ptr->free_me &= ~PNG_FREE_TRNS; + /* png_ptr->trans_alpha is always independently allocated (not aliased + * with info_ptr->trans_alpha), so free it unconditionally. + */ + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; #endif inflateEnd(&png_ptr->zstream); @@ -1336,7 +1334,7 @@ * png_struct::chromaticities always exists since the simplified API * requires rgb-to-gray. The mDCV, cICP and cHRM chunks may all set it to * a non-sRGB value, so it needs to be checked but **only** if one of - * those chunks occured in the file. + * those chunks occurred in the file. */ /* Highest priority: check to be safe. */ if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV)) @@ -2676,7 +2674,7 @@ { r = back_r; g = back_g; - b = back_g; + b = back_b; } /* Compare the newly-created color-map entry with the one the @@ -2954,9 +2952,9 @@ { png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow = first_row + y * row_step; - png_const_bytep end_row = outrow + width; + png_const_bytep row_end = outrow + width; - /* Read read the libpng data into the temporary buffer. */ + /* Read the libpng data into the temporary buffer. */ png_read_row(png_ptr, inrow, NULL); /* Now process the row according to the processing option, note @@ -2967,7 +2965,7 @@ switch (proc) { case PNG_CMAP_GA: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { /* The data is always in the PNG order */ unsigned int gray = *inrow++; @@ -2996,7 +2994,7 @@ break; case PNG_CMAP_TRANS: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte gray = *inrow++; png_byte alpha = *inrow++; @@ -3013,7 +3011,7 @@ break; case PNG_CMAP_RGB: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); inrow += 3; @@ -3021,7 +3019,7 @@ break; case PNG_CMAP_RGB_ALPHA: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { unsigned int alpha = inrow[3]; @@ -3058,10 +3056,10 @@ */ if (inrow[0] & 0x80) back_i += 9; /* red */ if (inrow[0] & 0x40) back_i += 9; - if (inrow[0] & 0x80) back_i += 3; /* green */ - if (inrow[0] & 0x40) back_i += 3; - if (inrow[0] & 0x80) back_i += 1; /* blue */ - if (inrow[0] & 0x40) back_i += 1; + if (inrow[1] & 0x80) back_i += 3; /* green */ + if (inrow[1] & 0x40) back_i += 3; + if (inrow[2] & 0x80) back_i += 1; /* blue */ + if (inrow[2] & 0x40) back_i += 1; *outrow = (png_byte)back_i; } @@ -3328,18 +3326,18 @@ { png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow; - png_const_bytep end_row; + png_const_bytep row_end; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); outrow = png_voidcast(png_bytep, display->first_row); outrow += y * row_step; - end_row = outrow + width * channels; + row_end = outrow + width * channels; /* Now do the composition on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte alpha = inrow[channels]; @@ -3512,14 +3510,14 @@ png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow = first_row + y * row_step; - png_const_bytep end_row = outrow + width; + png_const_bytep row_end = outrow + width; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); /* Now do the composition on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte alpha = inrow[1]; @@ -3557,14 +3555,14 @@ png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow = first_row + y * row_step; - png_const_bytep end_row = outrow + width; + png_const_bytep row_end = outrow + width; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); /* Now do the composition on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte alpha = inrow[1]; @@ -3647,7 +3645,7 @@ { png_const_uint_16p inrow; png_uint_16p outrow = first_row + y * row_step; - png_uint_16p end_row = outrow + width * outchannels; + png_uint_16p row_end = outrow + width * outchannels; /* Read the row, which is packed: */ png_read_row(png_ptr, png_voidcast(png_bytep, @@ -3657,7 +3655,7 @@ /* Now do the pre-multiplication on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_uint_32 component = inrow[0]; png_uint_16 alpha = inrow[1]; @@ -4193,7 +4191,7 @@ row_stride = (png_int_32)/*SAFE*/png_row_stride; if (row_stride < 0) - check = (png_uint_32)(-row_stride); + check = -(png_uint_32)row_stride; else check = (png_uint_32)row_stride; diff -Nru firefox-esr-140.9.0esr/media/libpng/pngrtran.c firefox-esr-140.9.1esr/media/libpng/pngrtran.c --- firefox-esr-140.9.0esr/media/libpng/pngrtran.c 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngrtran.c 2026-04-03 15:52:26.000000000 +0000 @@ -230,7 +230,7 @@ * * Terminology (assuming power law, "gamma", encodings): * "screen" gamma: a power law imposed by the output device when digital - * samples are converted to visible light output. The EOTF - volage to + * samples are converted to visible light output. The EOTF - voltage to * luminance on output. * * "file" gamma: a power law used to encode luminance levels from the input @@ -495,6 +495,9 @@ if (png_rtran_ok(png_ptr, 0) == 0) return; + if (palette == NULL) + return; + png_ptr->transformations |= PNG_QUANTIZE; if (full_quantize == 0) @@ -811,7 +814,13 @@ } if (png_ptr->palette == NULL) { - png_ptr->palette = palette; + /* Allocate an owned copy rather than aliasing the caller's pointer, + * so that png_read_destroy can free png_ptr->palette unconditionally. + */ + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + memcpy(png_ptr->palette, palette, (unsigned int)num_palette * + (sizeof (png_color))); } png_ptr->num_palette = (png_uint_16)num_palette; @@ -1364,7 +1373,7 @@ if (file_gamma != 0) return file_gamma; - /* If png_reciprocal oveflows it returns 0 which indicates to the caller that + /* If png_reciprocal overflows, it returns 0, indicating to the caller that * there is no usable file gamma. (The checks added to png_set_gamma and * png_set_alpha_mode should prevent a screen_gamma which would overflow.) */ @@ -2061,6 +2070,21 @@ { png_debug(1, "in png_read_transform_info"); + if (png_ptr->transformations != 0) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + info_ptr->palette != NULL && png_ptr->palette != NULL) + { + /* Sync info_ptr->palette with png_ptr->palette. + * The function png_init_read_transformations may have modified + * png_ptr->palette in place (e.g. for gamma correction or for + * background compositing). + */ + memcpy(info_ptr->palette, png_ptr->palette, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))); + } + } + #ifdef PNG_READ_EXPAND_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND) != 0) { diff -Nru firefox-esr-140.9.0esr/media/libpng/pngrutil.c firefox-esr-140.9.1esr/media/libpng/pngrutil.c --- firefox-esr-140.9.0esr/media/libpng/pngrutil.c 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngrutil.c 2026-04-03 15:52:26.000000000 +0000 @@ -436,7 +436,7 @@ * be gained by using this when it is known *if* the zlib stream itself does * not record the number; however, this is an illusion: the original writer * of the PNG may have selected a lower window size, and we really must - * follow that because, for systems with with limited capabilities, we + * follow that because, for systems with limited capabilities, we * would otherwise reject the application's attempts to use a smaller window * size (zlib doesn't have an interface to say "this or lower"!). * @@ -1011,7 +1011,7 @@ * in the case of an 8-bit display with a decoder which controls the palette. * * The alternative here is to ignore the error and store the palette anyway; - * destroying the tRNS will definately cause problems. + * destroying the tRNS will definitely cause problems. * * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and @@ -1058,19 +1058,6 @@ /* A valid PLTE chunk has been read */ png_ptr->mode |= PNG_HAVE_PLTE; - /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to - * its own copy of the palette. This has the side effect that when - * png_start_row is called (this happens after any call to - * png_read_update_info) the info_ptr palette gets changed. This is - * extremely unexpected and confusing. - * - * REVIEW: there have been consistent bugs in the past about gamma and - * similar transforms to colour mapped images being useless because the - * modified palette cannot be accessed because of the above. - * - * CONSIDER: Fix this by not sharing the palette in this way. But does - * this completely fix the problem? - */ png_set_PLTE(png_ptr, info_ptr, palette, num); return handled_ok; } @@ -1272,7 +1259,7 @@ /* png_set_cHRM may complain about some of the values but this doesn't matter * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous) - * values. Ridiculousity will be checked if the values are used later. + * values. Ridiculosity will be checked if the values are used later. */ png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy, xy.greenx, xy.greeny, xy.bluex, xy.bluey); @@ -1569,7 +1556,8 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_bytep entry_start, buffer; + png_bytep buffer; + png_bytep entry_start; png_sPLT_t new_palette; png_sPLT_entryp pp; png_uint_32 data_length; @@ -1776,10 +1764,6 @@ return handled_error; } - /* TODO: this is a horrible side effect in the palette case because the - * png_struct ends up with a pointer to the tRNS buffer owned by the - * png_info. Fix this. - */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, &(png_ptr->trans_color)); return handled_ok; @@ -2038,7 +2022,7 @@ return handled_error; /* PNGv3: the code used to check the byte order mark at the start for MM or - * II, however PNGv3 states that the the first 4 bytes should be checked. + * II, however PNGv3 states that the first 4 bytes should be checked. * The caller ensures that there are four bytes available. */ { @@ -2160,9 +2144,13 @@ static png_handle_result_code /* PRIVATE */ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { + png_bytep buffer; + png_bytep buf; + png_bytep endptr; png_int_32 X0, X1; - png_byte type, nparams; - png_bytep buffer, buf, units, endptr; + png_byte type; + png_byte nparams; + png_byte *units; png_charpp params; int i; @@ -3190,7 +3178,7 @@ png_uint_32 max_length :12; /* Length min, max in bytes */ png_uint_32 min_length :8; /* Length errors on critical chunks have special handling to preserve the - * existing behaviour in libpng 1.6. Anciallary chunks are checked below + * existing behaviour in libpng 1.6. Ancillary chunks are checked below * and produce a 'benign' error. */ png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */ @@ -3198,7 +3186,7 @@ /* NOTE: PLTE, tRNS and bKGD require special handling which depends on * the colour type of the base image. */ - png_uint_32 multiple :1; /* Multiple occurences permitted */ + png_uint_32 multiple :1; /* Multiple occurrences permitted */ /* This is enabled for PLTE because PLTE may, in practice, be optional */ } read_chunks[PNG_INDEX_unknown] = @@ -3232,7 +3220,7 @@ # define CDIHDR 13U, 13U, hIHDR, 0, 0 # define CDPLTE NoCheck, 0U, 0, hIHDR, 1 /* PLTE errors are only critical for colour-map images, consequently the - * hander does all the checks. + * handler does all the checks. */ # define CDIDAT NoCheck, 0U, aIDAT, hIHDR, 1 # define CDIEND NoCheck, 0U, 0, aIDAT, 0 diff -Nru firefox-esr-140.9.0esr/media/libpng/pngset.c firefox-esr-140.9.1esr/media/libpng/pngset.c --- firefox-esr-140.9.0esr/media/libpng/pngset.c 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngset.c 2026-04-03 15:52:26.000000000 +0000 @@ -1,6 +1,6 @@ /* pngset.c - storage of image information into info struct * - * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -333,7 +333,8 @@ png_debug1(1, "in %s storage function", "eXIf"); if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_eXIf) != 0) + (png_ptr->mode & PNG_WROTE_eXIf) != 0 || + exif == NULL) return; new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif)); @@ -388,7 +389,7 @@ png_debug1(1, "in %s storage function", "hIST"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || hist == NULL) return; if (info_ptr->num_palette == 0 || info_ptr->num_palette @@ -780,28 +781,38 @@ png_error(png_ptr, "Invalid palette"); } - /* It may not actually be necessary to set png_ptr->palette here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - * - * 1.6.0: the above statement appears to be incorrect; something has to set - * the palette inside png_struct on read. - */ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead * of num_palette entries, in case of an invalid PNG file or incorrect * call to png_set_PLTE() with too-large sample values. + * + * Allocate independent buffers for info_ptr and png_ptr so that the + * lifetime of png_ptr->palette is decoupled from the lifetime of + * info_ptr->palette. Previously, these two pointers were aliased, + * which caused a use-after-free vulnerability if png_free_data freed + * info_ptr->palette while png_ptr->palette was still in use by the + * row transform functions (e.g. png_do_expand_palette). + * + * Both buffers are allocated with png_calloc to zero-fill, because + * the ARM NEON palette riffle reads all 256 entries unconditionally, + * regardless of num_palette. */ + png_free(png_ptr, png_ptr->palette); png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette; if (num_palette > 0) + { + memcpy(info_ptr->palette, palette, (unsigned int)num_palette * + (sizeof (png_color))); memcpy(png_ptr->palette, palette, (unsigned int)num_palette * (sizeof (png_color))); + } - info_ptr->palette = png_ptr->palette; - info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; info_ptr->free_me |= PNG_FREE_PLTE; info_ptr->valid |= PNG_INFO_PLTE; } @@ -1159,28 +1170,40 @@ if (trans_alpha != NULL) { - /* It may not actually be necessary to set png_ptr->trans_alpha here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - * - * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively - * relies on png_set_tRNS storing the information in png_struct - * (otherwise it won't be there for the code in pngrtran.c). - */ - png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) { - /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + /* Allocate info_ptr's copy of the transparency data. + * Initialize all entries to fully opaque (0xff), then overwrite + * the first num_trans entries with the actual values. + */ info_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH); memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans); - info_ptr->free_me |= PNG_FREE_TRNS; info_ptr->valid |= PNG_INFO_tRNS; + + /* Allocate an independent copy for png_struct, so that the + * lifetime of png_ptr->trans_alpha is decoupled from the + * lifetime of info_ptr->trans_alpha. Previously these two + * pointers were aliased, which caused a use-after-free if + * png_free_data freed info_ptr->trans_alpha while + * png_ptr->trans_alpha was still in use by the row transform + * functions (e.g. png_do_expand_palette). + */ + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH); + memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans); + } + else + { + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; } - png_ptr->trans_alpha = info_ptr->trans_alpha; } if (trans_color != NULL) @@ -2018,7 +2041,7 @@ #endif /* BENIGN_ERRORS */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Whether to report invalid palette index; added at libng-1.5.10. + /* Whether to report invalid palette index; added at libpng-1.5.10. * It is possible for an indexed (color-type==3) PNG file to contain * pixels with invalid (out-of-range) indexes if the PLTE chunk has * fewer entries than the image's bit-depth would allow. We recover diff -Nru firefox-esr-140.9.0esr/media/libpng/pngstruct.h firefox-esr-140.9.1esr/media/libpng/pngstruct.h --- firefox-esr-140.9.0esr/media/libpng/pngstruct.h 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngstruct.h 2026-04-03 15:52:26.000000000 +0000 @@ -1,6 +1,6 @@ /* pngstruct.h - internal structures for libpng * - * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -106,7 +106,7 @@ * TODO: C23: convert these macros to C23 inlines (which are static). */ #define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i))) - /* The flag coresponding to the given png_index enum value. This is defined + /* The flag corresponding to the given png_index enum value. This is defined * for png_unknown as well (until it reaches the value 32) but this should * not be relied on. */ @@ -115,7 +115,7 @@ (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0) /* The chunk has been recorded in png_struct */ -#define png_file_add_chunk(pnt_ptr, i)\ +#define png_file_add_chunk(png_ptr, i)\ ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i))) /* Record the chunk in the png_struct */ diff -Nru firefox-esr-140.9.0esr/media/libpng/pngtrans.c firefox-esr-140.9.1esr/media/libpng/pngtrans.c --- firefox-esr-140.9.0esr/media/libpng/pngtrans.c 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngtrans.c 2026-04-03 15:52:26.000000000 +0000 @@ -1,6 +1,6 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -84,9 +84,38 @@ { png_debug(1, "in png_set_shift"); - if (png_ptr == NULL) + if (png_ptr == NULL || true_bits == NULL) return; + /* Check the shift values before passing them on to png_do_shift. */ + { + png_byte bit_depth = png_ptr->bit_depth; + int invalid = 0; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + if (true_bits->red == 0 || true_bits->red > bit_depth || + true_bits->green == 0 || true_bits->green > bit_depth || + true_bits->blue == 0 || true_bits->blue > bit_depth) + invalid = 1; + } + else + { + if (true_bits->gray == 0 || true_bits->gray > bit_depth) + invalid = 1; + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 && + (true_bits->alpha == 0 || true_bits->alpha > bit_depth)) + invalid = 1; + + if (invalid) + { + png_app_error(png_ptr, "png_set_shift: invalid shift values"); + return; + } + } + png_ptr->transformations |= PNG_SHIFT; png_ptr->shift = *true_bits; } @@ -457,10 +486,9 @@ if (row_info->bit_depth < 8) { + png_const_bytep table; png_bytep rp; - png_const_bytep end, table; - - end = row + row_info->rowbytes; + png_bytep row_end = row + row_info->rowbytes; if (row_info->bit_depth == 1) table = onebppswaptable; @@ -474,7 +502,7 @@ else return; - for (rp = row; rp < end; rp++) + for (rp = row; rp < row_end; rp++) *rp = table[*rp]; } } diff -Nru firefox-esr-140.9.0esr/media/libpng/pngwrite.c firefox-esr-140.9.1esr/media/libpng/pngwrite.c --- firefox-esr-140.9.0esr/media/libpng/pngwrite.c 2026-03-17 09:42:16.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngwrite.c 2026-04-03 15:52:26.000000000 +0000 @@ -163,7 +163,7 @@ * them. * * PNG v3: Chunks mDCV and cLLI provide ancillary information for the - * interpretation of the colourspace chunkgs but do not require support for + * interpretation of the colourspace chunks but do not require support for * those chunks so are outside the "COLORSPACE" check but before the write of * the colourspace chunks themselves. */ @@ -1019,6 +1019,16 @@ png_ptr->chunk_list = NULL; #endif +#if defined(PNG_tRNS_SUPPORTED) + /* Free the independent copy of trans_alpha owned by png_struct. */ + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; +#endif + + /* Free the independent copy of the palette owned by png_struct. */ + png_free(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; + /* The error handling and memory handling information is left intact at this * point: the jmp_buf may still have to be freed. See png_destroy_png_struct * for how this happens. @@ -2029,7 +2039,7 @@ display->row_stride = (png_int_32)/*SAFE*/png_row_stride; if (display->row_stride < 0) - check = (png_uint_32)(-display->row_stride); + check = -(png_uint_32)display->row_stride; else check = (png_uint_32)display->row_stride; @@ -2228,7 +2238,7 @@ static void (PNGCBAPI -image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size) +image_memory_write)(png_structp png_ptr, png_bytep data, size_t size) { png_image_write_control *display = png_voidcast(png_image_write_control*, png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); diff -Nru firefox-esr-140.9.0esr/media/libpng/pngwutil.c firefox-esr-140.9.1esr/media/libpng/pngwutil.c --- firefox-esr-140.9.0esr/media/libpng/pngwutil.c 2026-03-17 09:42:15.000000000 +0000 +++ firefox-esr-140.9.1esr/media/libpng/pngwutil.c 2026-04-03 15:52:25.000000000 +0000 @@ -1,6 +1,6 @@ /* pngwutil.c - utilities to write a PNG file * - * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -909,7 +909,6 @@ png_debug1(3, "num_palette = %d", png_ptr->num_palette); png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); -#ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) { @@ -919,21 +918,6 @@ png_write_chunk_data(png_ptr, buf, 3); } -#else - /* This is a little slower but some buggy compilers need to do this - * instead - */ - pal_ptr=palette; - - for (i = 0; i < num_pal; i++) - { - buf[0] = pal_ptr[i].red; - buf[1] = pal_ptr[i].green; - buf[2] = pal_ptr[i].blue; - png_write_chunk_data(png_ptr, buf, 3); - } - -#endif png_write_chunk_end(png_ptr); png_ptr->mode |= PNG_HAVE_PLTE; } @@ -1232,9 +1216,6 @@ size_t entry_size = (spalette->depth == 8 ? 6 : 10); size_t palette_size = entry_size * (size_t)spalette->nentries; png_sPLT_entryp ep; -#ifndef PNG_POINTER_INDEXING_SUPPORTED - int i; -#endif png_debug(1, "in png_write_sPLT"); @@ -1252,7 +1233,6 @@ png_write_chunk_data(png_ptr, &spalette->depth, 1); /* Loop through each palette entry, writing appropriately */ -#ifdef PNG_POINTER_INDEXING_SUPPORTED for (ep = spalette->entries; epentries + spalette->nentries; ep++) { if (spalette->depth == 8) @@ -1275,31 +1255,6 @@ png_write_chunk_data(png_ptr, entrybuf, entry_size); } -#else - ep=spalette->entries; - for (i = 0; i>spalette->nentries; i++) - { - if (spalette->depth == 8) - { - entrybuf[0] = (png_byte)ep[i].red; - entrybuf[1] = (png_byte)ep[i].green; - entrybuf[2] = (png_byte)ep[i].blue; - entrybuf[3] = (png_byte)ep[i].alpha; - png_save_uint_16(entrybuf + 4, ep[i].frequency); - } - - else - { - png_save_uint_16(entrybuf + 0, ep[i].red); - png_save_uint_16(entrybuf + 2, ep[i].green); - png_save_uint_16(entrybuf + 4, ep[i].blue); - png_save_uint_16(entrybuf + 6, ep[i].alpha); - png_save_uint_16(entrybuf + 8, ep[i].frequency); - } - - png_write_chunk_data(png_ptr, entrybuf, entry_size); - } -#endif png_write_chunk_end(png_ptr); } @@ -1769,7 +1724,7 @@ } new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; - ++key_len; /* for the keywod separator */ + ++key_len; /* for the keyword separator */ /* We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of diff -Nru firefox-esr-140.9.0esr/netwerk/cookie/CookieStorage.cpp firefox-esr-140.9.1esr/netwerk/cookie/CookieStorage.cpp --- firefox-esr-140.9.0esr/netwerk/cookie/CookieStorage.cpp 2026-03-17 09:42:17.000000000 +0000 +++ firefox-esr-140.9.1esr/netwerk/cookie/CookieStorage.cpp 2026-04-03 15:52:27.000000000 +0000 @@ -551,6 +551,8 @@ CookieEntry* aEntry, Cookie* aCookie, const nsACString& aBaseDomain, nsCOMPtr& aPurgedList) { MOZ_ASSERT(aEntry); + CookieKey key(aEntry->mBaseDomain, aEntry->mOriginAttributes); + // remove insecure older cookies until we are within the byte limit // so CHIPS-partitioned cookies will not be detected here since they must be // secure @@ -570,11 +572,17 @@ // remove secure older cookies until we are within the byte limit if (!underLimit) { + // Re-lookup: aEntry may have been freed if pass 1 emptied it. + CookieEntry* entry = mHostTable.GetEntry(key); + if (!entry) { + return; + } MOZ_LOG(gCookieLog, LogLevel::Debug, ("Still too many cookies for partition, purging secure\n")); - MaybePurgeList maybePurgeList(aEntry->GetCookies().Length()); - for (CookieEntry::IndexType i = 0; i < cookies.Length(); ++i) { - CookieListIter iter(aEntry, i); + const CookieEntry::ArrayType& secureCookies = entry->GetCookies(); + MaybePurgeList maybePurgeList(secureCookies.Length()); + for (CookieEntry::IndexType i = 0; i < secureCookies.Length(); ++i) { + CookieListIter iter(entry, i); maybePurgeList.AppendElement(iter); } maybePurgeList.Sort(CompareCookiesByAge()); diff -Nru firefox-esr-140.9.0esr/netwerk/dns/DNSPacket.cpp firefox-esr-140.9.1esr/netwerk/dns/DNSPacket.cpp --- firefox-esr-140.9.0esr/netwerk/dns/DNSPacket.cpp 2026-03-17 09:42:17.000000000 +0000 +++ firefox-esr-140.9.1esr/netwerk/dns/DNSPacket.cpp 2026-04-03 15:52:27.000000000 +0000 @@ -52,6 +52,13 @@ return mStatus; } + if (static_cast(response_length) > MAX_SIZE) { + LOG(("FillBuffer response len %d > MAX_SIZE %u", response_length, MAX_SIZE)); + mBodySize = 0; + mStatus = NS_ERROR_UNEXPECTED; + return mStatus; + } + mBodySize = response_length; return NS_OK; } diff -Nru firefox-esr-140.9.0esr/sourcestamp.txt firefox-esr-140.9.1esr/sourcestamp.txt --- firefox-esr-140.9.0esr/sourcestamp.txt 2026-03-17 11:25:01.000000000 +0000 +++ firefox-esr-140.9.1esr/sourcestamp.txt 2026-04-03 15:52:56.000000000 +0000 @@ -1,2 +1,2 @@ -20260317093326 -https://hg.mozilla.org/releases/mozilla-esr140/rev/ad4a5ceb5516151b4014e2af6c1565c68ab330cc +20260403140708 +https://hg.mozilla.org/releases/mozilla-esr140/rev/cca515379f569261e903f6e84dcdb0ecdbbe821e diff -Nru firefox-esr-140.9.0esr/testing/web-platform/meta/fedcm/lfedcm-identity.create-store-collect.tentative.sub.https.html.ini firefox-esr-140.9.1esr/testing/web-platform/meta/fedcm/lfedcm-identity.create-store-collect.tentative.sub.https.html.ini --- firefox-esr-140.9.0esr/testing/web-platform/meta/fedcm/lfedcm-identity.create-store-collect.tentative.sub.https.html.ini 2026-03-17 09:42:19.000000000 +0000 +++ firefox-esr-140.9.1esr/testing/web-platform/meta/fedcm/lfedcm-identity.create-store-collect.tentative.sub.https.html.ini 2026-04-03 15:52:29.000000000 +0000 @@ -1,6 +1,7 @@ [lfedcm-identity.create-store-collect.tentative.sub.https.html] expected: if (os == "mac") and not debug: [OK, TIMEOUT] + if asan or tsan: TIMEOUT [Collecting from no providers yields a promise with null resolution] expected: FAIL @@ -10,7 +11,9 @@ [Credentials can be collected silently, but preventSilentAccess is respected] expected: if (os == "mac") and not debug: [PASS, NOTRUN] + if asan or tsan: NOTRUN [Cross-origin identity credential collection is correctly filtered when the type does not match] expected: if (os == "mac") and not debug: [PASS, TIMEOUT] + if asan or tsan: TIMEOUT