Version in base suite: 140.8.0esr-1~deb13u1 Version in overlay suite: 140.10.1esr-1~deb13u1 Base version: firefox-esr_140.10.1esr-1~deb13u1 Target version: firefox-esr_140.10.2esr-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/f/firefox-esr/firefox-esr_140.10.1esr-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/f/firefox-esr/firefox-esr_140.10.2esr-1~deb13u1.dsc browser/config/version.txt | 2 browser/config/version_display.txt | 2 config/milestone.txt | 2 debian/changelog | 8 + debian/control | 2 dom/canvas/WebGLContext.cpp | 8 + dom/fetch/InternalResponse.cpp | 6 dom/fetch/InternalResponse.h | 6 dom/filesystem/FileSystemSecurity.cpp | 36 ++++ dom/filesystem/FileSystemUtils.cpp | 29 --- dom/filesystem/FileSystemUtils.h | 6 dom/indexedDB/ActorsParent.cpp | 29 ++- dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp | 2 dom/serviceworkers/FetchEventOpProxyChild.cpp | 16 -- dom/serviceworkers/ServiceWorkerOp.cpp | 13 + dom/serviceworkers/ServiceWorkerOpPromise.h | 5 dom/url/URL.cpp | 4 dom/url/URL.h | 2 gfx/angle/checkout/src/libANGLE/State.cpp | 2 gfx/angle/checkout/src/libANGLE/renderer/d3d/TextureD3D.cpp | 25 ++- gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 16 +- gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h | 7 gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h | 15 + gfx/cairo/cairo/src/cairo-cff-subset.c | 6 gfx/cairo/cairo/src/cairo-pdf-surface.c | 16 +- gfx/layers/DcompSurfaceImage.cpp | 33 ++++ gfx/layers/ipc/ContentCompositorBridgeParent.cpp | 3 gfx/skia/skia/include/core/SkRegion.h | 15 + gfx/skia/skia/src/core/SkRegion.cpp | 62 +++++-- gfx/skia/skia/src/core/SkRegionPriv.h | 3 ipc/glue/BackgroundParentImpl.cpp | 4 layout/generic/nsTextFrame.cpp | 2 layout/reftests/bugs/1798297-1-notref.html | 17 -- layout/reftests/bugs/reftest.list | 1 modules/freetype2/src/truetype/ttinterp.c | 6 sourcestamp.txt | 4 taskcluster/gecko_taskgraph/transforms/test/variant.py | 4 testing/mochitest/browser-test.js | 14 - testing/mochitest/tests/SimpleTest/SimpleTest.js | 14 - testing/modules/Mochia.js | 21 +- testing/web-platform/meta/webrtc/RTCPeerConnection-getStats-timestamp.https.html.ini | 3 third_party/libwebrtc/api/rtp_parameters.cc | 8 - third_party/libwebrtc/common_audio/ring_buffer.c | 5 third_party/libwebrtc/common_audio/ring_buffer_unittest.cc | 3 third_party/libwebrtc/media/engine/webrtc_voice_engine.cc | 26 ++- third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc | 31 +++ third_party/libwebrtc/modules/audio_coding/BUILD.gn | 2 third_party/libwebrtc/modules/audio_coding/DEPS | 1 third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler.cc | 13 + third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler_unittest.cc | 79 ++++++++++ third_party/libwebrtc/modules/audio_coding/neteq/normal.cc | 57 +++---- third_party/libwebrtc/modules/audio_coding/neteq/normal.h | 4 third_party/libwebrtc/modules/audio_coding/neteq/normal_unittest.cc | 14 + third_party/libwebrtc/modules/video_coding/BUILD.gn | 1 third_party/libwebrtc/modules/video_coding/codecs/av1/BUILD.gn | 2 third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc | 7 third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc | 79 ++++++++++ third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc | 5 third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc | 70 ++++++++ third_party/libwebrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc | 22 ++ third_party/libwebrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc | 51 ++++++ third_party/libwebrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc | 14 + third_party/libwebrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc | 50 ++++++ third_party/libwebrtc/modules/video_coding/video_codec_initializer.cc | 8 - third_party/libwebrtc/pc/sdp_offer_answer.cc | 6 third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc | 40 +++++ third_party/libwebrtc/rtc_base/BUILD.gn | 1 third_party/libwebrtc/rtc_base/strings/string_builder.cc | 10 - third_party/libwebrtc/rtc_base/strings/string_builder.h | 7 third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc | 38 ---- third_party/libwebrtc/video/video_receive_stream2.cc | 3 toolkit/components/telemetry/tests/marionette/tests/client/test_shutdown_pings_succeed.py | 10 - widget/windows/nsWindowGfx.cpp | 2 73 files changed, 856 insertions(+), 284 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpm72fda2c/firefox-esr_140.10.1esr-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpm72fda2c/firefox-esr_140.10.2esr-1~deb13u1.dsc: no acceptable signature found diff -Nru firefox-esr-140.10.1esr/browser/config/version.txt firefox-esr-140.10.2esr/browser/config/version.txt --- firefox-esr-140.10.1esr/browser/config/version.txt 2026-04-27 16:08:50.000000000 +0000 +++ firefox-esr-140.10.2esr/browser/config/version.txt 2026-05-06 14:54:36.000000000 +0000 @@ -1 +1 @@ -140.10.1 +140.10.2 diff -Nru firefox-esr-140.10.1esr/browser/config/version_display.txt firefox-esr-140.10.2esr/browser/config/version_display.txt --- firefox-esr-140.10.1esr/browser/config/version_display.txt 2026-04-27 16:08:50.000000000 +0000 +++ firefox-esr-140.10.2esr/browser/config/version_display.txt 2026-05-06 14:54:36.000000000 +0000 @@ -1 +1 @@ -140.10.1esr +140.10.2esr diff -Nru firefox-esr-140.10.1esr/config/milestone.txt firefox-esr-140.10.2esr/config/milestone.txt --- firefox-esr-140.10.1esr/config/milestone.txt 2026-04-27 16:08:51.000000000 +0000 +++ firefox-esr-140.10.2esr/config/milestone.txt 2026-05-06 14:54:36.000000000 +0000 @@ -10,4 +10,4 @@ # hardcoded milestones in the tree from these two files. #-------------------------------------------------------- -140.10.1 +140.10.2 diff -Nru firefox-esr-140.10.1esr/debian/changelog firefox-esr-140.10.2esr/debian/changelog --- firefox-esr-140.10.1esr/debian/changelog 2026-04-28 22:57:41.000000000 +0000 +++ firefox-esr-140.10.2esr/debian/changelog 2026-05-07 23:22:51.000000000 +0000 @@ -1,3 +1,11 @@ +firefox-esr (140.10.2esr-1~deb13u1) trixie-security; urgency=medium + + * New upstream release. + * Fixes for mfsa2026-41, also known as: + CVE-2026-8090, CVE-2026-8094, CVE-2026-8092. + + -- Mike Hommey Fri, 08 May 2026 08:22:51 +0900 + firefox-esr (140.10.1esr-1~deb13u1) trixie-security; urgency=medium * New upstream release. diff -Nru firefox-esr-140.10.1esr/debian/control firefox-esr-140.10.2esr/debian/control --- firefox-esr-140.10.1esr/debian/control 2026-04-28 22:57:41.000000000 +0000 +++ firefox-esr-140.10.2esr/debian/control 2026-05-07 23:22:51.000000000 +0000 @@ -59,7 +59,7 @@ procps, debianutils (>= 1.16), libnspr4 (>= 2:4.32~), -Recommends: libavcodec61 | libavcodec-extra61 | libavcodec60 | libavcodec-extra60 | libavcodec59 | libavcodec-extra59 | libavcodec58 | libavcodec-extra58 | libavcodec57 | libavcodec-extra57 | libavcodec56 | libavcodec-extra56 | libavcodec55 | libavcodec-extra55 | libavcodec54 | libavcodec-extra54 | libavcodec53 | libavcodec-extra53 +Recommends: libavcodec62 | libavcodec-extra62 | libavcodec61 | libavcodec-extra61 | libavcodec60 | libavcodec-extra60 | libavcodec59 | libavcodec-extra59 | libavcodec58 | libavcodec-extra58 | libavcodec57 | libavcodec-extra57 | libavcodec56 | libavcodec-extra56 | libavcodec55 | libavcodec-extra55 | libavcodec54 | libavcodec-extra54 | libavcodec53 | libavcodec-extra53 Suggests: fonts-stix | otf-stix, fonts-lmodern, libgssapi-krb5-2 | libkrb53, diff -Nru firefox-esr-140.10.1esr/dom/canvas/WebGLContext.cpp firefox-esr-140.10.2esr/dom/canvas/WebGLContext.cpp --- firefox-esr-140.10.1esr/dom/canvas/WebGLContext.cpp 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/canvas/WebGLContext.cpp 2026-05-06 14:54:37.000000000 +0000 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "AccessCheck.h" @@ -2823,6 +2824,13 @@ state.imageHeight = subrectSize.y; } + constexpr uint32_t kGLintMax = std::numeric_limits::max(); + if (state.rowLength > kGLintMax || state.imageHeight > kGLintMax || + state.skipPixels > kGLintMax || state.skipRows > kGLintMax || + state.skipImages > kGLintMax) { + return Err("pixelStorei params must be GLint."); + } + // - const auto mpii = PackingInfoInfo::For(pi); diff -Nru firefox-esr-140.10.1esr/dom/fetch/InternalResponse.cpp firefox-esr-140.10.2esr/dom/fetch/InternalResponse.cpp --- firefox-esr-140.10.1esr/dom/fetch/InternalResponse.cpp 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/fetch/InternalResponse.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -158,11 +158,13 @@ } void InternalResponse::ToChildToParentInternalResponse( - ChildToParentInternalResponse* aIPCResponse, - mozilla::ipc::PBackgroundChild* aManager) { + ChildToParentInternalResponse* aIPCResponse) { *aIPCResponse = ChildToParentInternalResponse(GetMetadata(), Nothing(), UNKNOWN_BODY_SIZE, Nothing()); +} +void InternalResponse::SerializeChildToParentInternalResponseBody( + ChildToParentInternalResponse* aIPCResponse) { nsCOMPtr body; int64_t bodySize; GetUnfilteredBody(getter_AddRefs(body), &bodySize); diff -Nru firefox-esr-140.10.1esr/dom/fetch/InternalResponse.h firefox-esr-140.10.2esr/dom/fetch/InternalResponse.h --- firefox-esr-140.10.1esr/dom/fetch/InternalResponse.h 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/fetch/InternalResponse.h 2026-05-06 14:54:38.000000000 +0000 @@ -52,8 +52,10 @@ const ParentToParentInternalResponse& aIPCResponse); void ToChildToParentInternalResponse( - ChildToParentInternalResponse* aIPCResponse, - mozilla::ipc::PBackgroundChild* aManager); + ChildToParentInternalResponse* aIPCResponse); + + void SerializeChildToParentInternalResponseBody( + ChildToParentInternalResponse* aIPCResponse); ParentToParentInternalResponse ToParentToParentInternalResponse(); diff -Nru firefox-esr-140.10.1esr/dom/filesystem/FileSystemSecurity.cpp firefox-esr-140.10.2esr/dom/filesystem/FileSystemSecurity.cpp --- firefox-esr-140.10.1esr/dom/filesystem/FileSystemSecurity.cpp 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/filesystem/FileSystemSecurity.cpp 2026-05-06 14:54:37.000000000 +0000 @@ -16,6 +16,40 @@ StaticRefPtr gFileSystemSecurity; +#if defined(XP_WIN) +constexpr char16_t kWindowsPathSeparator = '\\'; +constexpr char16_t kPlatformPathSeparator = kWindowsPathSeparator; +#else +constexpr char16_t kPosixPathSeparator = '/'; +constexpr char16_t kPlatformPathSeparator = kPosixPathSeparator; +#endif + +bool IsDescendantPath(const nsAString& aAuthorizedRoot, + const nsAString& aRequestedDescendant) { + // Check the sub-directory path to see if it has the parent path as prefix. + if (aRequestedDescendant.Equals(aAuthorizedRoot)) { + return true; + } + + if (!StringBeginsWith(/*aSource*/ aRequestedDescendant, + /*aSubstring*/ aAuthorizedRoot)) { + return false; + } + + // Require a path separator immediately after the granted prefix. + const uint32_t prefixLen = aAuthorizedRoot.Length(); + if (prefixLen > 0 && aAuthorizedRoot.Last() == kPlatformPathSeparator) { + return true; + } + + if (aRequestedDescendant.Length() <= prefixLen || + aRequestedDescendant.CharAt(prefixLen) != kPlatformPathSeparator) { + return false; + } + + return true; +} + } // namespace /* static */ @@ -97,7 +131,7 @@ MOZ_DIAGNOSTIC_ASSERT(paths); for (const auto& authorizedRoot : *paths) { - if (FileSystemUtils::IsDescendantPath(authorizedRoot, aPath)) { + if (IsDescendantPath(authorizedRoot, aPath)) { return true; } } diff -Nru firefox-esr-140.10.1esr/dom/filesystem/FileSystemUtils.cpp firefox-esr-140.10.2esr/dom/filesystem/FileSystemUtils.cpp --- firefox-esr-140.10.1esr/dom/filesystem/FileSystemUtils.cpp 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/filesystem/FileSystemUtils.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -12,35 +12,6 @@ namespace mozilla::dom { /* static */ -bool FileSystemUtils::IsDescendantPath(const nsAString& aAuthorizedRoot, - const nsAString& aRequestedDescendant) { - // Check the sub-directory path to see if it has the parent path as prefix. - if (aRequestedDescendant.Equals(aAuthorizedRoot)) { - return true; - } - - if (!StringBeginsWith(/*aSource*/ aRequestedDescendant, - /*aSubstring*/ aAuthorizedRoot)) { - return false; - } - - // Require a path separator immediately after the granted prefix. - const uint32_t prefixLen = aAuthorizedRoot.Length(); - if (prefixLen > 0 && - aAuthorizedRoot.Last() == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR) { - return true; - } - - if (aRequestedDescendant.Length() <= prefixLen || - aRequestedDescendant.CharAt(prefixLen) != - FILESYSTEM_DOM_PATH_SEPARATOR_CHAR) { - return false; - } - - return true; -} - -/* static */ bool FileSystemUtils::IsValidRelativeDOMPath(const nsAString& aPath, nsTArray& aParts) { // We don't allow empty relative path to access the root. diff -Nru firefox-esr-140.10.1esr/dom/filesystem/FileSystemUtils.h firefox-esr-140.10.2esr/dom/filesystem/FileSystemUtils.h --- firefox-esr-140.10.1esr/dom/filesystem/FileSystemUtils.h 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/filesystem/FileSystemUtils.h 2026-05-06 14:54:38.000000000 +0000 @@ -25,12 +25,6 @@ */ class FileSystemUtils { public: - /* - * Return true if aDescendantPath is a descendant of aPath. - */ - static bool IsDescendantPath(const nsAString& aPath, - const nsAString& aDescendantPath); - /** * Return true if this is valid DOMPath. It also splits the path in * subdirectories and stores them in aParts. diff -Nru firefox-esr-140.10.1esr/dom/indexedDB/ActorsParent.cpp firefox-esr-140.10.2esr/dom/indexedDB/ActorsParent.cpp --- firefox-esr-140.10.1esr/dom/indexedDB/ActorsParent.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/indexedDB/ActorsParent.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -1914,6 +1914,7 @@ InternalState mInternalState = InternalState::Initial; bool mWaitingForContinue = false; const bool mTransactionIsAborted; + bool mNotedActiveRequest = false; protected: const int64_t mTransactionLoggingSerialNumber; @@ -1981,6 +1982,8 @@ ~TransactionDatabaseOperationBase() override; + void NoteTransactionActiveRequest(); + virtual void RunOnConnectionThread(); // Must be overridden in subclasses. Called on the target thread to allow the @@ -6710,10 +6713,14 @@ return nullptr; } - if (NS_AUUF_OR_WARN_IF(!aLoggingInfo.nextTransactionSerialNumber()) || + // Requests and normal transaction serial numbers must stay positive. + // VersionChange transaction serial numbers must stay negative. + // https://searchfox.org/firefox-main/rev/8332a06d47ce7d66623d807068b3410061cd29d3/dom/indexedDB/ActorsChild.cpp#82 + if (NS_AUUF_OR_WARN_IF(aLoggingInfo.nextTransactionSerialNumber() <= 0) || + NS_AUUF_OR_WARN_IF( + aLoggingInfo.nextVersionChangeTransactionSerialNumber() >= 0) || NS_AUUF_OR_WARN_IF( - !aLoggingInfo.nextVersionChangeTransactionSerialNumber()) || - NS_AUUF_OR_WARN_IF(!aLoggingInfo.nextRequestSerialNumber())) { + static_cast(aLoggingInfo.nextRequestSerialNumber()) <= 0)) { return nullptr; } @@ -15912,7 +15919,7 @@ mVersionChangeOp = versionChangeOp; - mVersionChangeTransaction->NoteActiveRequest(); + versionChangeOp->NoteTransactionActiveRequest(); mVersionChangeTransaction->Init(transactionId); return NS_OK; @@ -17065,6 +17072,7 @@ TransactionDatabaseOperationBase::~TransactionDatabaseOperationBase() { MOZ_ASSERT(mInternalState == InternalState::Completed); + MOZ_ASSERT(!mNotedActiveRequest); MOZ_ASSERT(!mTransaction, "TransactionDatabaseOperationBase::Cleanup() was not called by a " "subclass!"); @@ -17197,6 +17205,14 @@ Unused << this->Run(); } +void TransactionDatabaseOperationBase::NoteTransactionActiveRequest() { + AssertIsOnOwningThread(); + MOZ_ASSERT(!mNotedActiveRequest); + + (*mTransaction)->NoteActiveRequest(); + mNotedActiveRequest = true; +} + void TransactionDatabaseOperationBase::SendToConnectionPool() { AssertIsOnOwningThread(); MOZ_ASSERT(mInternalState == InternalState::Initial); @@ -17207,7 +17223,7 @@ gConnectionPool->Dispatch((*mTransaction)->TransactionId(), this); - (*mTransaction)->NoteActiveRequest(); + NoteTransactionActiveRequest(); } void TransactionDatabaseOperationBase::SendPreprocess() { @@ -17282,8 +17298,9 @@ mWaitingForContinue = true; } else { - if (mLoggingSerialNumber) { + if (mNotedActiveRequest) { (*mTransaction)->NoteFinishedRequest(mRequestId, ResultCode()); + mNotedActiveRequest = false; } Cleanup(); diff -Nru firefox-esr-140.10.1esr/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp firefox-esr-140.10.2esr/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp --- firefox-esr-140.10.1esr/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -35,6 +35,7 @@ static const char* sLibs[] = { // clang-format off #if defined(XP_DARWIN) + "libavcodec.62.dylib", "libavcodec.61.dylib", "libavcodec.60.dylib", "libavcodec.59.dylib", @@ -48,6 +49,7 @@ "libavcodec.so", // OpenBSD hardly controls the major/minor library version // of ffmpeg and update it regulary on ABI/API changes #else + "libavcodec.so.62", "libavcodec.so.61", "libavcodec.so.60", "libavcodec.so.59", diff -Nru firefox-esr-140.10.1esr/dom/serviceworkers/FetchEventOpProxyChild.cpp firefox-esr-140.10.2esr/dom/serviceworkers/FetchEventOpProxyChild.cpp --- firefox-esr-140.10.1esr/dom/serviceworkers/FetchEventOpProxyChild.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/serviceworkers/FetchEventOpProxyChild.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -39,20 +39,12 @@ ChildToParentSynthesizeResponseArgs* aIPCArgs, SynthesizeResponseArgs&& aArgs) { MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread()); + auto [internalResponse, ipcArgs] = std::move(aArgs); - auto [internalResponse, closure, timeStamps] = std::move(aArgs); + *aIPCArgs = std::move(ipcArgs); - aIPCArgs->closure() = std::move(closure); - aIPCArgs->timeStamps() = std::move(timeStamps); - - PBackgroundChild* bgChild = BackgroundChild::GetOrCreateForCurrentThread(); - - if (NS_WARN_IF(!bgChild)) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - internalResponse->ToChildToParentInternalResponse( - &aIPCArgs->internalResponse(), bgChild); + internalResponse->SerializeChildToParentInternalResponseBody( + &aIPCArgs->internalResponse()); return NS_OK; } diff -Nru firefox-esr-140.10.1esr/dom/serviceworkers/ServiceWorkerOp.cpp firefox-esr-140.10.2esr/dom/serviceworkers/ServiceWorkerOp.cpp --- firefox-esr-140.10.1esr/dom/serviceworkers/ServiceWorkerOp.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/serviceworkers/ServiceWorkerOp.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -1699,10 +1699,17 @@ ir->SnapshotUnfilteredHeaders(); mHandled->MaybeResolveWithUndefined(); + + ChildToParentSynthesizeResponseArgs synthesizeResponseArgs; + synthesizeResponseArgs.closure() = mRespondWithClosure.ref(); + synthesizeResponseArgs.timeStamps() = + FetchEventTimeStamps(mFetchHandlerStart, mFetchHandlerFinish); + ir->ToChildToParentInternalResponse( + &synthesizeResponseArgs.internalResponse()); + mRespondWithPromiseHolder.Resolve( - FetchEventRespondWithResult(std::make_tuple( - std::move(ir), mRespondWithClosure.ref(), - FetchEventTimeStamps(mFetchHandlerStart, mFetchHandlerFinish))), + FetchEventRespondWithResult( + std::make_pair(std::move(ir), std::move(synthesizeResponseArgs))), __func__); } diff -Nru firefox-esr-140.10.1esr/dom/serviceworkers/ServiceWorkerOpPromise.h firefox-esr-140.10.2esr/dom/serviceworkers/ServiceWorkerOpPromise.h --- firefox-esr-140.10.1esr/dom/serviceworkers/ServiceWorkerOpPromise.h 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/serviceworkers/ServiceWorkerOpPromise.h 2026-05-06 14:54:38.000000000 +0000 @@ -18,9 +18,8 @@ class InternalResponse; -using SynthesizeResponseArgs = - std::tuple, FetchEventRespondWithClosure, - FetchEventTimeStamps>; +using SynthesizeResponseArgs = std::pair, + ChildToParentSynthesizeResponseArgs>; using FetchEventRespondWithResult = Variant URL::SearchParams() { CreateSearchParamsIfNeeded(); - return mSearchParams; + return do_AddRef(mSearchParams); } void URL::CreateSearchParamsIfNeeded() { diff -Nru firefox-esr-140.10.1esr/dom/url/URL.h firefox-esr-140.10.2esr/dom/url/URL.h --- firefox-esr-140.10.1esr/dom/url/URL.h 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/dom/url/URL.h 2026-05-06 14:54:38.000000000 +0000 @@ -104,7 +104,7 @@ void GetSearch(nsACString& aSearch) const; void SetSearch(const nsACString& aSearch); - URLSearchParams* SearchParams(); + already_AddRefed SearchParams(); void GetHash(nsACString& aHash) const; void SetHash(const nsACString& aHash); diff -Nru firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/State.cpp firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/State.cpp --- firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/State.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/State.cpp 2026-05-06 14:54:39.000000000 +0000 @@ -1902,7 +1902,7 @@ bool State::removeDrawFramebufferBinding(FramebufferID framebuffer) { - if (mReadFramebuffer != nullptr && mDrawFramebuffer->id() == framebuffer) + if (mDrawFramebuffer != nullptr && mDrawFramebuffer->id() == framebuffer) { setDrawFramebufferBinding(nullptr); return true; diff -Nru firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/TextureD3D.cpp firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/TextureD3D.cpp --- firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/TextureD3D.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/TextureD3D.cpp 2026-05-06 14:54:39.000000000 +0000 @@ -786,7 +786,10 @@ onStateChange(angle::SubjectMessage::StorageReleased); auto err = mTexStorage->onDestroy(context); - SafeDelete(mTexStorage); + if (!IsError(err)) + { + SafeDelete(mTexStorage); + } return err; } @@ -874,9 +877,23 @@ const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); GLuint imageBytes = 0; - ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeRowPitch(formatInfo.type, image->getWidth(), - 1, 0, &imageBytes)); - imageBytes *= image->getHeight() * image->getDepth(); + if (formatInfo.compressed) + { + ANGLE_CHECK_GL_MATH( + contextD3D, formatInfo.computeCompressedImageSize( + gl::Extents(image->getWidth(), image->getHeight(), image->getDepth()), + &imageBytes)); + } + else + { + ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeRowPitch( + formatInfo.type, image->getWidth(), 1, 0, &imageBytes)); + + angle::CheckedNumeric checkedImageBytes(imageBytes); + checkedImageBytes *= image->getHeight(); + checkedImageBytes *= image->getDepth(); + ANGLE_CHECK_GL_MATH(contextD3D, checkedImageBytes.AssignIfValid(&imageBytes)); + } gl::PixelUnpackState zeroDataUnpackState; zeroDataUnpackState.alignment = 1; diff -Nru firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp --- firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp 2026-04-27 16:08:52.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -893,7 +893,9 @@ return a.second.lruCount < b.second.lruCount; }); - ASSERT(iter->second.storage != newStorage); + if (iter->second.storage == newStorage) + break; + ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize()); mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize(); @@ -959,7 +961,9 @@ return a.second.lruCount < b.second.lruCount; }); - ASSERT(iter->second.storage != newStorage); + if (iter->second.storage == newStorage) + break; + ASSERT(mStructuredBufferStorageAdditionalSize >= iter->second.storage->getSize()); mStructuredBufferStorageAdditionalSize -= iter->second.storage->getSize(); @@ -1594,8 +1598,12 @@ ANGLE_TRY(attribute.computeOffset(context, startVertex, &offset)); // Expand the memory storage upon request and cache the results. - unsigned int expandedDataSize = - static_cast((indexInfo->srcCount * attribute.stride) + offset); + angle::CheckedNumeric checkedExpandedDataSize(indexInfo->srcCount); + checkedExpandedDataSize *= attribute.stride; + checkedExpandedDataSize += offset; + ANGLE_CHECK_GL_MATH(context11, + checkedExpandedDataSize.IsValid()); + unsigned int expandedDataSize = checkedExpandedDataSize.ValueOrDie(); angle::MemoryBuffer expandedData; ANGLE_CHECK_GL_ALLOC(context11, expandedData.resize(expandedDataSize)); diff -Nru firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h --- firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h 2026-05-06 14:54:39.000000000 +0000 @@ -318,12 +318,7 @@ friend class ResourceManager11; SharedResource11(Resource11 &&obj) : Resource11Base>() { - std::swap(this->mData->manager, obj.mData->manager); - - // Can't use std::swap because of ID3D11Resource. - auto temp = this->mData->object; - this->mData->object = obj.mData->object; - obj.mData->object = static_cast(temp); + this->mData = std::move(obj.mData); } }; diff -Nru firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h --- firefox-esr-140.10.1esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h 2026-05-06 14:54:39.000000000 +0000 @@ -352,7 +352,9 @@ struct GenericData { GenericData() {} - ~GenericData() + ~GenericData() { reset(); } + + void reset() { if (object) { @@ -395,12 +397,13 @@ template void init(Resource11 &&texture, const DescT &desc, const d3d11::Format &format) { - std::swap(mData->manager, texture.mData->manager); + // Release previous resource, if any. + mData->reset(); - // Can't use std::swap because texture is typed, and here we use ID3D11Resource. - ID3D11Resource *temp = mData->object; - mData->object = texture.mData->object; - texture.mData->object = static_cast(temp); + mData->manager = texture.mData->manager; + texture.mData->manager = nullptr; + mData->object = texture.mData->object; + texture.mData->object = nullptr; mFormatSet = &format; initDesc(desc); diff -Nru firefox-esr-140.10.1esr/gfx/cairo/cairo/src/cairo-cff-subset.c firefox-esr-140.10.2esr/gfx/cairo/cairo/src/cairo-cff-subset.c --- firefox-esr-140.10.1esr/gfx/cairo/cairo/src/cairo-cff-subset.c 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/cairo/cairo/src/cairo-cff-subset.c 2026-05-06 14:54:38.000000000 +0000 @@ -1415,7 +1415,11 @@ if (sid < NUM_STD_STRINGS) return CAIRO_STATUS_SUCCESS; - element = _cairo_array_index (&font->strings_index, sid - NUM_STD_STRINGS); + sid -= NUM_STD_STRINGS; + if (sid >= (int)_cairo_array_num_elements (&font->strings_index)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + element = _cairo_array_index (&font->strings_index, sid); sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); status = cff_index_append (&font->strings_subset_index, element->data, element->length); if (unlikely (status)) diff -Nru firefox-esr-140.10.1esr/gfx/cairo/cairo/src/cairo-pdf-surface.c firefox-esr-140.10.2esr/gfx/cairo/cairo/src/cairo-pdf-surface.c --- firefox-esr-140.10.1esr/gfx/cairo/cairo/src/cairo-pdf-surface.c 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/cairo/cairo/src/cairo-pdf-surface.c 2026-05-06 14:54:38.000000000 +0000 @@ -3084,7 +3084,8 @@ unsigned long alpha_size; uint32_t *pixel32; uint8_t *pixel8; - int i, x, y, bit, a; + unsigned long i; + int x, y, bit, a; cairo_image_transparency_t transparency; /* This is the only image format we support, which simplifies things. */ @@ -3102,10 +3103,10 @@ } if (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA || transparency == CAIRO_IMAGE_IS_OPAQUE) { - alpha_size = (image->width + 7) / 8 * image->height; + alpha_size = (unsigned long) ((image->width + 7) / 8) * image->height; alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height); } else { - alpha_size = image->height * image->width; + alpha_size = (unsigned long) image->height * image->width; alpha = _cairo_malloc_ab (image->height, image->width); } @@ -3220,7 +3221,8 @@ char *data; unsigned long data_size; uint32_t *pixel; - int i, x, y, bit; + unsigned long i; + int x, y, bit; cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */ cairo_bool_t need_smask; cairo_image_color_t color; @@ -3268,16 +3270,16 @@ case CAIRO_IMAGE_UNKNOWN_COLOR: ASSERT_NOT_REACHED; case CAIRO_IMAGE_IS_COLOR: - data_size = image->height * image->width * 3; + data_size = (unsigned long) image->height * image->width * 3; data = _cairo_malloc_abc (image->width, image->height, 3); break; case CAIRO_IMAGE_IS_GRAYSCALE: - data_size = image->height * image->width; + data_size = (unsigned long) image->height * image->width; data = _cairo_malloc_ab (image->width, image->height); break; case CAIRO_IMAGE_IS_MONOCHROME: - data_size = (image->width + 7) / 8 * image->height; + data_size = (unsigned long) ((image->width + 7) / 8) * image->height; data = _cairo_malloc_ab ((image->width+7) / 8, image->height); break; } diff -Nru firefox-esr-140.10.1esr/gfx/layers/DcompSurfaceImage.cpp firefox-esr-140.10.2esr/gfx/layers/DcompSurfaceImage.cpp --- firefox-esr-140.10.1esr/gfx/layers/DcompSurfaceImage.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/layers/DcompSurfaceImage.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -19,10 +19,43 @@ namespace mozilla::layers { +static constexpr int32_t kMaxDcompSurfaceDimension = 16384; + +static bool IsValidDcompSurfaceDescriptor( + const SurfaceDescriptorDcompSurface& aDescriptor) { + if (!aDescriptor.handle().IsValid()) { + gfxCriticalNote << "DcompSurfaceHandleHost: invalid FileDescriptor"; + return false; + } + + const gfx::SurfaceFormat fmt = aDescriptor.format(); + if (fmt != gfx::SurfaceFormat::B8G8R8A8 && + fmt != gfx::SurfaceFormat::R8G8B8A8) { + gfxCriticalNote << "DcompSurfaceHandleHost: unsupported format " + << static_cast(fmt); + return false; + } + + const gfx::IntSize size = aDescriptor.size(); + if (size.width <= 0 || size.height <= 0 || + size.width > kMaxDcompSurfaceDimension || + size.height > kMaxDcompSurfaceDimension) { + gfxCriticalNote << "DcompSurfaceHandleHost: bad size " << size.width << "x" + << size.height; + return false; + } + + return true; +} + already_AddRefed CreateTextureHostDcompSurface( const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator, LayersBackend aBackend, TextureFlags aFlags) { MOZ_ASSERT(aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorDcompSurface); + if (!IsValidDcompSurfaceDescriptor( + aDesc.get_SurfaceDescriptorDcompSurface())) { + return nullptr; + } RefPtr result = new DcompSurfaceHandleHost( aFlags, aDesc.get_SurfaceDescriptorDcompSurface()); return result.forget(); diff -Nru firefox-esr-140.10.1esr/gfx/layers/ipc/ContentCompositorBridgeParent.cpp firefox-esr-140.10.2esr/gfx/layers/ipc/ContentCompositorBridgeParent.cpp --- firefox-esr-140.10.1esr/gfx/layers/ipc/ContentCompositorBridgeParent.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/layers/ipc/ContentCompositorBridgeParent.cpp 2026-05-06 14:54:38.000000000 +0000 @@ -386,6 +386,9 @@ const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock, const LayersBackend& aLayersBackend, const TextureFlags& aFlags, const uint64_t& aSerial, const wr::MaybeExternalImageId& aExternalImageId) { + if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorDcompSurface) { + return nullptr; + } return TextureHost::CreateIPDLActor( this, aSharedData, std::move(aReadLock), aLayersBackend, aFlags, mCompositorManager->GetContentId(), aSerial, aExternalImageId); diff -Nru firefox-esr-140.10.1esr/gfx/skia/skia/include/core/SkRegion.h firefox-esr-140.10.2esr/gfx/skia/skia/include/core/SkRegion.h --- firefox-esr-140.10.1esr/gfx/skia/skia/include/core/SkRegion.h 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/skia/skia/include/core/SkRegion.h 2026-05-06 14:54:39.000000000 +0000 @@ -441,8 +441,9 @@ #endif /** \class SkRegion::Iterator - Returns sequence of rectangles, sorted along y-axis, then x-axis, that make - up SkRegion. + Goes through the region one rectangle at a time. For each "strip" of one or more contiguous + Y values (scanlines) in ascending order, the iterator returns each rectangle in that strip + (from left to right) before advancing to the next strip (which may or may not have a gap). */ class SK_API Iterator { public: @@ -488,9 +489,12 @@ bool done() const { return fDone; } /** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done. - - example: https://fiddle.skia.org/c/@Region_Iterator_next - */ + * This moves to the next rectangle to the right within the current + * horizontal strip. If the end of the strip is reached, it automatically + * advances to the first rectangle in the next strip, skipping any vertical gaps. + * + * example: https://fiddle.skia.org/c/@Region_Iterator_next + */ void next(); /** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion @@ -508,6 +512,7 @@ private: const SkRegion* fRgn; + // See top of SkRegion.cpp for more on the RLE encoding const SkRegion::RunType* fRuns; SkIRect fRect = {0, 0, 0, 0}; bool fDone; diff -Nru firefox-esr-140.10.1esr/gfx/skia/skia/src/core/SkRegion.cpp firefox-esr-140.10.2esr/gfx/skia/skia/src/core/SkRegion.cpp --- firefox-esr-140.10.1esr/gfx/skia/skia/src/core/SkRegion.cpp 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/skia/skia/src/core/SkRegion.cpp 2026-05-06 14:54:39.000000000 +0000 @@ -23,14 +23,30 @@ using namespace skia_private; -/* Region Layout +/* SkRegion Run-Length Encoding (RLE) Format: * - * TOP + * A region is stored as a series of non-overlapping horizontal strips (scanlines). + * All rectangles in a strip share the same Top and Bottom Y-coordinates. * - * [ Bottom, X-Intervals, [Left, Right]..., X-Sentinel ] - * ... + * Data layout: + * [Top-Y] + * [Bottom-Y, Interval-Count (N), Left-1, Right-1, ..., Left-N, Right-N, X-Sentinel] + * [Bottom-Y, Interval-Count (M), Left-1, Right-1, ..., Left-M, Right-M, X-Sentinel] + * ... + * [Y-Sentinel] * - * Y-Sentinel + * - Sentinels are 0x7FFFFFFF (SkRegion_kRunTypeSentinel). + * - Interval-Count can be 0 (representing a vertical gap between strips). + * - Strips are sorted by Y; Intervals within a strip are sorted by X. + * + * Example: Two rects [10, 10, 20, 20] and [30, 10, 40, 20] on one line, + * then a gap until Y=30, then [15, 30, 25, 40] would be: + * + * 10 // Global Top-Y + * 20, 2, 10, 20, 30, 40, S // Strip 1: Y 10-20, 2 rects, X-Sentinel + * 30, 0, S // Strip 2: Y 20-30, 0 rects (gap), X-Sentinel + * 40, 1, 15, 25, S // Strip 3: Y 30-40, 1 rect, X-Sentinel + * S // Y-Sentinel */ ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -98,6 +114,10 @@ return const_cast(runs); } +static inline void assert_sentinel(int32_t value, bool isSentinel) { + SkASSERT(SkRegionValueIsSentinel(value) == isSentinel); +} + bool SkRegion::RunsAreARect(const SkRegion::RunType runs[], int count, SkIRect* bounds) { assert_sentinel(runs[0], false); // top @@ -299,7 +319,7 @@ if (runs[3] == SkRegion_kRunTypeSentinel) { // should be first left... runs += 3; // skip empty initial span runs[0] = runs[-2]; // set new top to prev bottom - assert_sentinel(runs[1], false); // bot: a sentinal would mean two in a row + assert_sentinel(runs[1], false); // bot: a sentinel would mean two in a row assert_sentinel(runs[2], false); // intervalcount assert_sentinel(runs[3], false); // left assert_sentinel(runs[4], false); // right @@ -879,7 +899,7 @@ int flush() { (*fArray)[fStartDst] = fTop; - // Previously reserved enough for TWO sentinals. + // Previously reserved enough for TWO sentinels. SkASSERT(fArray->count() > SkToInt(fPrevDst + fPrevLen)); (*fArray)[fPrevDst + fPrevLen] = SkRegion_kRunTypeSentinel; return (int)(fPrevDst - fStartDst + fPrevLen + 1); @@ -1050,20 +1070,18 @@ // swith to using pointers, so we can swap them as needed const SkRegion* rgna = &rgnaOrig; const SkRegion* rgnb = &rgnbOrig; - // after this point, do not refer to rgnaOrig or rgnbOrig!!! - // collaps difference and reverse-difference into just difference + // collapse difference and reverse-difference into just difference if (kReverseDifference_Op == op) { - using std::swap; - swap(rgna, rgnb); + std::swap(rgna, rgnb); op = kDifference_Op; } SkIRect bounds; - bool a_empty = rgna->isEmpty(); - bool b_empty = rgnb->isEmpty(); - bool a_rect = rgna->isRect(); - bool b_rect = rgnb->isRect(); + bool a_empty = rgna->isEmpty(); + bool b_empty = rgnb->isEmpty(); + bool a_rect = rgna->isRect(); + bool b_rect = rgnb->isRect(); switch (op) { case kDifference_Op: @@ -1188,9 +1206,11 @@ } SkSafeMath safeMath; int sum = 2; + // 3 bytes per ySpan (stop Y, how many intervals, sentinel) sum = safeMath.addInt(sum, ySpanCount); sum = safeMath.addInt(sum, ySpanCount); sum = safeMath.addInt(sum, ySpanCount); + // 2 bytes per interval (startX, stop X) sum = safeMath.addInt(sum, intervalCount); sum = safeMath.addInt(sum, intervalCount); return safeMath && sum == runCount; @@ -1218,6 +1238,7 @@ const int32_t* const end = runs + runCount; SkIRect bounds = {0, 0, 0 ,0}; // calulated bounds SkIRect rect = {0, 0, 0, 0}; // current rect + bool prevWasEmpty = true; // If we start with an empty slice, that's corrupted data. rect.fTop = *runs++; if (rect.fTop == SkRegion_kRunTypeSentinel) { return false; // no rect can contain SkRegion_kRunTypeSentinel @@ -1246,6 +1267,15 @@ if (xIntervals < 0 || xIntervals > intervalCount || runs + 1 + 2 * xIntervals > end) { return false; } + if (xIntervals == 0) { + if (prevWasEmpty) { + // back to back empty spans are invalid; our serialization always has them together + return false; + } + prevWasEmpty = true; + } else { + prevWasEmpty = false; + } intervalCount -= xIntervals; bool firstInterval = true; int32_t lastRight = 0; // check that x-intervals are distinct and ordered. @@ -1263,7 +1293,7 @@ bounds.join(rect); } if (*runs++ != SkRegion_kRunTypeSentinel) { - return false; // required check sentinal. + return false; // required check sentinel. } rect.fTop = rect.fBottom; SkASSERT(runs < end); diff -Nru firefox-esr-140.10.1esr/gfx/skia/skia/src/core/SkRegionPriv.h firefox-esr-140.10.2esr/gfx/skia/skia/src/core/SkRegionPriv.h --- firefox-esr-140.10.1esr/gfx/skia/skia/src/core/SkRegionPriv.h 2026-04-27 16:08:53.000000000 +0000 +++ firefox-esr-140.10.2esr/gfx/skia/skia/src/core/SkRegionPriv.h 2026-05-06 14:54:39.000000000 +0000 @@ -38,9 +38,6 @@ return value == (int32_t)SkRegion_kRunTypeSentinel; } -#define assert_sentinel(value, isSentinel) \ - SkASSERT(SkRegionValueIsSentinel(value) == isSentinel) - #ifdef SK_DEBUG // Given the first interval (just past the interval-count), compute the // interval count, by search for the x-sentinel diff -Nru firefox-esr-140.10.1esr/ipc/glue/BackgroundParentImpl.cpp firefox-esr-140.10.2esr/ipc/glue/BackgroundParentImpl.cpp --- firefox-esr-140.10.1esr/ipc/glue/BackgroundParentImpl.cpp 2026-04-27 16:08:54.000000000 +0000 +++ firefox-esr-140.10.2esr/ipc/glue/BackgroundParentImpl.cpp 2026-05-06 14:54:40.000000000 +0000 @@ -511,6 +511,9 @@ already_AddRefed BackgroundParentImpl::AllocPRemoteWorkerControllerParent( const dom::RemoteWorkerData& aRemoteWorkerData) { + if (BackgroundParent::IsOtherProcessActor(this)) { + return nullptr; + } RefPtr actor = new dom::RemoteWorkerControllerParent(aRemoteWorkerData); return actor.forget(); @@ -520,7 +523,6 @@ dom::PRemoteWorkerControllerParent* aActor, const dom::RemoteWorkerData& aRemoteWorkerData) { MOZ_ASSERT(aActor); - return IPC_OK(); } diff -Nru firefox-esr-140.10.1esr/layout/generic/nsTextFrame.cpp firefox-esr-140.10.2esr/layout/generic/nsTextFrame.cpp --- firefox-esr-140.10.1esr/layout/generic/nsTextFrame.cpp 2026-04-27 16:08:58.000000000 +0000 +++ firefox-esr-140.10.2esr/layout/generic/nsTextFrame.cpp 2026-05-06 14:54:43.000000000 +0000 @@ -7440,7 +7440,7 @@ if (frag->IsHighSurrogateFollowedByLowSurrogateAt(offs) && gfxFontUtils::IsRegionalIndicator(frag->ScalarValueAt(offs))) { allowSplitLigature = false; - if (extraCluster.GetSkippedOffset() > 1 && + if (extraCluster.GetSkippedOffset() >= skippedRange.start + 2 && !mTextRun->IsLigatureGroupStart(extraCluster.GetSkippedOffset())) { // CountCharsFit() left us in the middle of the flag; back up over the // first character of the ligature, and adjust fitWidth accordingly. diff -Nru firefox-esr-140.10.1esr/layout/reftests/bugs/1798297-1-notref.html firefox-esr-140.10.2esr/layout/reftests/bugs/1798297-1-notref.html --- firefox-esr-140.10.1esr/layout/reftests/bugs/1798297-1-notref.html 2026-04-27 16:08:58.000000000 +0000 +++ firefox-esr-140.10.2esr/layout/reftests/bugs/1798297-1-notref.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ - - - - -Coordination of kern and palt features for CJK kerning - - -

Enabling font-kerning:normal should NOT apply 'palt' for the Yu Gothic UI font

-
幻塔 イラストコンテスト 開催
- - diff -Nru firefox-esr-140.10.1esr/layout/reftests/bugs/reftest.list firefox-esr-140.10.2esr/layout/reftests/bugs/reftest.list --- firefox-esr-140.10.1esr/layout/reftests/bugs/reftest.list 2026-04-27 16:08:58.000000000 +0000 +++ firefox-esr-140.10.2esr/layout/reftests/bugs/reftest.list 2026-05-06 14:54:43.000000000 +0000 @@ -2133,7 +2133,6 @@ pref(layout.css.prefers-color-scheme.content-override,2) == 1787127.html 1787127-ref.html == 1792643-1.html 1792643-1-ref.html skip-if(!winWidget) == 1798297-1.html 1798297-1-ref.html -skip-if(!winWidget) != 1798297-1.html 1798297-1-notref.html == 1799425-1.html 1799425-1-ref.html fuzzy-if(winWidget,111-114,572-572) == 1800437-1.html 1800437-1-ref.html == 1803999-1.html 1803999-1-ref.html diff -Nru firefox-esr-140.10.1esr/modules/freetype2/src/truetype/ttinterp.c firefox-esr-140.10.2esr/modules/freetype2/src/truetype/ttinterp.c --- firefox-esr-140.10.1esr/modules/freetype2/src/truetype/ttinterp.c 2026-04-27 16:08:59.000000000 +0000 +++ firefox-esr-140.10.2esr/modules/freetype2/src/truetype/ttinterp.c 2026-05-06 14:54:45.000000000 +0000 @@ -5337,13 +5337,11 @@ /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ /* Twilight zone has no real contours, so use `n_points'. */ /* Normal zone's `n_points' includes phantoms, so must */ - /* use end of last contour. */ + /* subtract them. */ if ( exc->GS.gep2 == 0 ) limit = exc->zp2.n_points; - else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) - limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1; else - limit = 0; + limit = exc->zp2.n_points - 4U; /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ for ( i = 0; i < limit; i++ ) diff -Nru firefox-esr-140.10.1esr/sourcestamp.txt firefox-esr-140.10.2esr/sourcestamp.txt --- firefox-esr-140.10.1esr/sourcestamp.txt 2026-04-27 16:09:28.000000000 +0000 +++ firefox-esr-140.10.2esr/sourcestamp.txt 2026-05-06 14:55:15.000000000 +0000 @@ -1,2 +1,2 @@ -20260427105827 -https://hg.mozilla.org/releases/mozilla-esr140/rev/a24e9e115e02794f72dab9ef6081244403b0183a +20260506114755 +https://hg.mozilla.org/releases/mozilla-esr140/rev/6220f392be743517c45c0a46b455d7a57c0b9891 diff -Nru firefox-esr-140.10.1esr/taskcluster/gecko_taskgraph/transforms/test/variant.py firefox-esr-140.10.2esr/taskcluster/gecko_taskgraph/transforms/test/variant.py --- firefox-esr-140.10.1esr/taskcluster/gecko_taskgraph/transforms/test/variant.py 2026-04-27 16:09:00.000000000 +0000 +++ firefox-esr-140.10.2esr/taskcluster/gecko_taskgraph/transforms/test/variant.py 2026-05-06 14:54:46.000000000 +0000 @@ -56,7 +56,9 @@ return [] if "esr" in config.params.get("release_type", ""): - return [] + # Bug 2005068 - ioi tests are tier 3 and permafailing on some + # suites on ESR140, don't waste resources running them. + return ["inc-origin-init", "privatebrowsing-inc-origin-init"] today = datetime.datetime.today() for variant in variants: diff -Nru firefox-esr-140.10.1esr/testing/mochitest/browser-test.js firefox-esr-140.10.2esr/testing/mochitest/browser-test.js --- firefox-esr-140.10.1esr/testing/mochitest/browser-test.js 2026-04-27 16:09:00.000000000 +0000 +++ firefox-esr-140.10.2esr/testing/mochitest/browser-test.js 2026-05-06 14:54:46.000000000 +0000 @@ -1307,6 +1307,12 @@ this.ContentTask.setTestScope(currentScope); + // Import Mochia methods in the test scope + Services.scriptloader.loadSubScript( + "resource://testing-common/Mochia.js", + scope + ); + // Allow Assert.sys.mjs methods to be tacked to the current scope. scope.export_assertions = function () { for (let func in this.Assert) { @@ -1936,11 +1942,3 @@ } }, }; - -/* import-globals-from ../modules/Mochia.js */ -Services.scriptloader.loadSubScript( - "resource://testing-common/Mochia.js", - this -); - -Mochia(testScope); diff -Nru firefox-esr-140.10.1esr/testing/mochitest/tests/SimpleTest/SimpleTest.js firefox-esr-140.10.2esr/testing/mochitest/tests/SimpleTest/SimpleTest.js --- firefox-esr-140.10.1esr/testing/mochitest/tests/SimpleTest/SimpleTest.js 2026-04-27 16:09:00.000000000 +0000 +++ firefox-esr-140.10.2esr/testing/mochitest/tests/SimpleTest/SimpleTest.js 2026-05-06 14:54:46.000000000 +0000 @@ -2250,6 +2250,12 @@ return add_task(generatorFunction, { isSetup: true }); } +// Import Mochia methods in the test scope +SpecialPowers.Services.scriptloader.loadSubScript( + "resource://testing-common/Mochia.js", + this +); + // Request complete log when using failure patterns so that failure info // from infra can be useful. if (usesFailurePatterns()) { @@ -2262,11 +2268,3 @@ SimpleTest.finish(); } }); - -/* import-globals-from ../../../modules/Mochia.js */ -SpecialPowers.Services.scriptloader.loadSubScript( - "resource://testing-common/Mochia.js", - this -); - -Mochia(this); diff -Nru firefox-esr-140.10.1esr/testing/modules/Mochia.js firefox-esr-140.10.2esr/testing/modules/Mochia.js --- firefox-esr-140.10.1esr/testing/modules/Mochia.js 2026-04-27 16:08:59.000000000 +0000 +++ firefox-esr-140.10.2esr/testing/modules/Mochia.js 2026-05-06 14:54:45.000000000 +0000 @@ -4,11 +4,8 @@ /** * Define Mochia's helpers on the given scope. - * - * @param {object} scope - * The `globalThis` of the running test, where `add_task` is defined. */ -const Mochia = (function () { +(() => { /** * The context of each test suite. */ @@ -246,14 +243,12 @@ }, }); - return function (scope) { - _testScope = scope; + _testScope = this; - Object.assign(_testScope, { - describe: MochiaImpl.describe, - beforeEach: MochiaImpl.beforeEach, - afterEach: MochiaImpl.afterEach, - it: MochiaImpl.it, - }); - }; + Object.assign(_testScope, { + describe: MochiaImpl.describe, + beforeEach: MochiaImpl.beforeEach, + afterEach: MochiaImpl.afterEach, + it: MochiaImpl.it, + }); })(); diff -Nru firefox-esr-140.10.1esr/testing/web-platform/meta/webrtc/RTCPeerConnection-getStats-timestamp.https.html.ini firefox-esr-140.10.2esr/testing/web-platform/meta/webrtc/RTCPeerConnection-getStats-timestamp.https.html.ini --- firefox-esr-140.10.1esr/testing/web-platform/meta/webrtc/RTCPeerConnection-getStats-timestamp.https.html.ini 2026-04-27 16:09:01.000000000 +0000 +++ firefox-esr-140.10.2esr/testing/web-platform/meta/webrtc/RTCPeerConnection-getStats-timestamp.https.html.ini 2026-05-06 14:54:48.000000000 +0000 @@ -4,5 +4,4 @@ if (os == "mac") and not debug: [PASS, FAIL] if (os == "linux") and (processor == "x86"): [PASS, FAIL] if (os == "linux") and not debug: [PASS, FAIL] - if (os == "win") and not debug and (processor == "x86"): [PASS, FAIL] - if not debug and (os == "win") and (processor == "x86_64"): [PASS, FAIL] + if os == "win": [PASS, FAIL] diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/api/rtp_parameters.cc firefox-esr-140.10.2esr/third_party/libwebrtc/api/rtp_parameters.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/api/rtp_parameters.cc 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/api/rtp_parameters.cc 2026-05-06 14:54:51.000000000 +0000 @@ -16,7 +16,6 @@ #include #include "absl/strings/string_view.h" -#include "api/array_view.h" #include "api/rtp_transceiver_direction.h" #include "media/base/media_constants.h" #include "rtc_base/checks.h" @@ -127,15 +126,14 @@ RtpParameters::~RtpParameters() = default; std::string RtpExtension::ToString() const { - char buf[256]; - SimpleStringBuilder sb(buf); + StringBuilder sb; sb << "{uri: " << uri; sb << ", id: " << id; if (encrypt) { sb << ", encrypt"; } - sb << '}'; - return sb.str(); + sb << "}"; + return sb.Release(); } constexpr char RtpExtension::kEncryptHeaderExtensionsUri[]; diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/common_audio/ring_buffer.c firefox-esr-140.10.2esr/third_party/libwebrtc/common_audio/ring_buffer.c --- firefox-esr-140.10.1esr/third_party/libwebrtc/common_audio/ring_buffer.c 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/common_audio/ring_buffer.c 2026-05-06 14:54:53.000000000 +0000 @@ -14,6 +14,7 @@ #include "common_audio/ring_buffer.h" #include // size_t +#include #include #include @@ -56,6 +57,10 @@ return NULL; } + if (element_count > SIZE_MAX / element_size) { + return NULL; + } + self = malloc(sizeof(RingBuffer)); if (!self) { return NULL; diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc 2026-05-06 14:54:51.000000000 +0000 @@ -14,6 +14,7 @@ #include #include +#include #include #include "test/gtest.h" @@ -142,6 +143,8 @@ TEST(RingBufferTest, CreateHandlesErrors) { EXPECT_TRUE(WebRtc_CreateBuffer(0, 1) == nullptr); EXPECT_TRUE(WebRtc_CreateBuffer(1, 0) == nullptr); + EXPECT_TRUE(WebRtc_CreateBuffer(SIZE_MAX, 2) == nullptr); + EXPECT_TRUE(WebRtc_CreateBuffer(2, SIZE_MAX) == nullptr); RingBuffer* buffer = WebRtc_CreateBuffer(1, 1); EXPECT_TRUE(buffer != nullptr); WebRtc_FreeBuffer(buffer); diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc firefox-esr-140.10.2esr/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc 2026-05-06 14:54:51.000000000 +0000 @@ -2603,9 +2603,14 @@ // it up to the *latest* unsignaled stream we've seen, in order to support // the case where the SSRC of one unsignaled stream changes. if (default_sink_) { - for (uint32_t drop_ssrc : unsignaled_recv_ssrcs_) { - auto it = recv_streams_.find(drop_ssrc); - it->second->SetRawAudioSink(nullptr); + // The new ssrc has already been appended to `unsignaled_recv_ssrcs_`. + // If there are 2 or more streams, the stream at `size - 2` is the previous + // latest stream which currently possesses the default sink. + if (unsignaled_recv_ssrcs_.size() >= 2) { + // Detach the default sink from the previous latest stream. + uint32_t prev_ssrc = + unsignaled_recv_ssrcs_[unsignaled_recv_ssrcs_.size() - 2]; + SetRawAudioSink(prev_ssrc, nullptr); } std::unique_ptr proxy_sink( new ProxySink(default_sink_.get())); @@ -2803,7 +2808,22 @@ RTC_DCHECK_RUN_ON(worker_thread_); auto it = absl::c_find(unsignaled_recv_ssrcs_, ssrc); if (it != unsignaled_recv_ssrcs_.end()) { + bool is_latest_unsignaled = (it == unsignaled_recv_ssrcs_.end() - 1); unsignaled_recv_ssrcs_.erase(it); + if (default_sink_) { + // Detach the default sink from the deregistered stream. This is needed + // to prevent the ProxySink from holding a dangling pointer to the + // default_sink_. + SetRawAudioSink(ssrc, nullptr); + if (is_latest_unsignaled && !unsignaled_recv_ssrcs_.empty()) { + // The deregistered stream was the latest unsignaled stream, so it held + // the default sink. Since it was removed, we must pass the default sink + // to the *new* latest unsignaled stream via a new ProxySink. + std::unique_ptr proxy_sink( + new ProxySink(default_sink_.get())); + SetRawAudioSink(unsignaled_recv_ssrcs_.back(), std::move(proxy_sink)); + } + } return true; } return false; diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc 2026-05-06 14:54:52.000000000 +0000 @@ -3795,6 +3795,37 @@ call_.GetNetworkState(webrtc::MediaType::VIDEO)); } +// Test that when an unsignaled stream is promoted to a signaled stream, +// its ProxySink doesn't hold a dangling raw pointer if the default sink +// is subsequently destroyed. +TEST_P(WebRtcVoiceEngineTestFake, + ProxySinkSurvivesUnsignaledToSignaledPromotion) { + EXPECT_TRUE(SetupChannel()); + std::unique_ptr fake_sink(new FakeAudioSink()); + + // Set the default sink. + receive_channel_->SetDefaultRawAudioSink(std::move(fake_sink)); + + // Deliver an RTP packet to create an unsignaled stream. + DeliverPacket(kPcmuFrame); + const AudioSinkInterface* proxy_sink = GetRecvStream(kSsrc1).sink(); + EXPECT_NE(nullptr, proxy_sink); + + // Promote the unsignaled stream to a signaled stream. + StreamParams sp = StreamParams::CreateLegacy(kSsrc1); + EXPECT_TRUE(receive_channel_->AddRecvStream(sp)); + + // The proxy sink should be removed from the stream upon promotion. + EXPECT_EQ(nullptr, GetRecvStream(kSsrc1).sink()); + + // Destroy the original sink by passing nullptr. + receive_channel_->SetDefaultRawAudioSink(nullptr); + + // Note: calling proxy_sink->OnData would crash here if the proxy_sink + // would still be attached to the stream and hold a dangling pointer to + // default_sink_. But we've verified that it's detached, so that won't happen. +} + // Test that playout is still started after changing parameters TEST_P(WebRtcVoiceEngineTestFake, PreservePlayoutWhenRecreateRecvStream) { SetupRecvStream(); diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/BUILD.gn firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/BUILD.gn --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/BUILD.gn 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/BUILD.gn 2026-05-06 14:54:51.000000000 +0000 @@ -47,6 +47,7 @@ "../../api/neteq:default_neteq_factory", "../../api/neteq:neteq_api", "../../api/units:timestamp", + "../../audio/utility:audio_frame_operations", "../../common_audio", "../../common_audio:common_audio_c", "../../rtc_base:audio_format_to_string", @@ -1353,6 +1354,7 @@ sources = [ "acm2/acm_remixing_unittest.cc", + "acm2/acm_resampler_unittest.cc", "acm2/audio_coding_module_unittest.cc", "acm2/call_statistics_unittest.cc", "audio_network_adaptor/audio_network_adaptor_impl_unittest.cc", diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/DEPS firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/DEPS --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/DEPS 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/DEPS 2026-05-06 14:54:52.000000000 +0000 @@ -1,4 +1,5 @@ include_rules = [ + "+audio/utility", "+call", "+common_audio", "+logging/rtc_event_log", diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler.cc 2026-05-06 14:54:52.000000000 +0000 @@ -13,6 +13,7 @@ #include #include "api/audio/audio_frame.h" +#include "audio/utility/audio_frame_operations.h" #include "rtc_base/logging.h" namespace webrtc { @@ -70,6 +71,18 @@ (desired_sample_rate_hz != -1) && (current_sample_rate_hz != desired_sample_rate_hz); + if (need_resampling) { + const size_t target_size = + audio_frame->num_channels_ * + SampleRateToDefaultChannelSize(desired_sample_rate_hz); + if (target_size > AudioFrame::kMaxDataSizeSamples) { + RTC_LOG(LS_ERROR) << "AudioFrame cannot hold resampled data."; + AudioFrameOperations::Mute(audio_frame); + audio_frame->SetSampleRateAndChannelSize(desired_sample_rate_hz); + return false; + } + } + if (need_resampling && !resampled_last_output_frame_) { // Prime the resampler with the last frame. int16_t temp_output[AudioFrame::kMaxDataSizeSamples]; diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler_unittest.cc 1970-01-01 00:00:00.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/acm2/acm_resampler_unittest.cc 2026-05-06 14:54:53.000000000 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_coding/acm2/acm_resampler.h" + +#include +#include +#include + +#include "api/audio/audio_frame.h" +#include "test/gtest.h" + +namespace webrtc { +namespace acm2 { + +TEST(ResamplerHelperTest, MaybeResampleCheckForMaxSize) { + ResamplerHelper resampler; + AudioFrame audio_frame; + + // Create an audio frame that requires resampling from 32kHz to 48kHz + // with a very high number of channels (24). + const int kCurrentSampleRateHz = 32000; + const int kDesiredSampleRateHz = 48000; + const size_t kChannels = 24; + + // 10 ms of data at 32kHz = 320 samples per channel. + std::vector dummy_data(320 * 24, 0); + audio_frame.UpdateFrame(0, dummy_data.data(), 320, kCurrentSampleRateHz, + AudioFrame::kNormalSpeech, AudioFrame::kVadActive, + kChannels); + + // The resampler prime path will attempt to allocate a buffer that is + // kChannels * (kDesiredSampleRateHz / 100) = 24 * 480 = 11520 samples, + // which exceeds AudioFrame::kMaxDataSizeSamples (7680). + const bool resample_success = + resampler.MaybeResample(kDesiredSampleRateHz, &audio_frame); + + // Verify that MaybeResample correctly detects the buffer size condition and + // safely aborts the operation by returning false and muting the frame. + EXPECT_FALSE(resample_success); + EXPECT_TRUE(audio_frame.muted()); + EXPECT_EQ(audio_frame.sample_rate_hz_, kDesiredSampleRateHz); + EXPECT_EQ(audio_frame.num_channels_, kChannels); +} + +TEST(ResamplerHelperTest, MaybeResampleValidMaxSize) { + ResamplerHelper resampler; + AudioFrame audio_frame; + + // Ensure that resampling within the valid buffer size does not trigger the + // muting behavior. We'll use a valid number of channels (e.g. 1) that will + // not exceed the bounds. + const int kCurrentSampleRateHz = 32000; + const int kDesiredSampleRateHz = 48000; + const size_t kChannels = 1; + + std::vector dummy_data(320 * 1, 1000); + audio_frame.UpdateFrame(0, dummy_data.data(), 320, kCurrentSampleRateHz, + AudioFrame::kNormalSpeech, AudioFrame::kVadActive, + kChannels); + + const bool resample_success = + resampler.MaybeResample(kDesiredSampleRateHz, &audio_frame); + + EXPECT_TRUE(resample_success); + EXPECT_FALSE(audio_frame.muted()); + EXPECT_EQ(audio_frame.sample_rate_hz_, kDesiredSampleRateHz); + EXPECT_EQ(audio_frame.num_channels_, kChannels); +} + +} // namespace acm2 +} // namespace webrtc diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.cc 2026-05-06 14:54:51.000000000 +0000 @@ -16,12 +16,32 @@ #include "common_audio/signal_processing/include/signal_processing_library.h" #include "modules/audio_coding/neteq/audio_multi_vector.h" +#include "modules/audio_coding/neteq/audio_vector.h" #include "modules/audio_coding/neteq/background_noise.h" #include "modules/audio_coding/neteq/decoder_database.h" #include "modules/audio_coding/neteq/expand.h" #include "rtc_base/checks.h" namespace webrtc { +namespace { + +void Crossfade(const AudioVector& from, AudioVector& to, size_t win_length) { + const size_t win_length_clamped = + std::min({win_length, from.Size(), to.Size()}); + if (win_length_clamped == 0) { + return; + } + int16_t win_slope_Q14 = (1 << 14) / static_cast(win_length_clamped); + int16_t win_up_Q14 = 0; + for (size_t i = 0; i < win_length_clamped; i++) { + win_up_Q14 += win_slope_Q14; + to[i] = + (win_up_Q14 * to[i] + ((1 << 14) - win_up_Q14) * from[i] + (1 << 13)) >> + 14; + } +} + +} // namespace int Normal::Process(const int16_t* input, size_t length, @@ -132,23 +152,7 @@ // Interpolate the expanded data into the new vector. // (NB/WB/SWB32/SWB48 8/16/32/48 samples.) - size_t win_length = samples_per_ms_; - int16_t win_slope_Q14 = default_win_slope_Q14_; - RTC_DCHECK_LT(channel_ix, output->Channels()); - if (win_length > output->Size()) { - win_length = output->Size(); - win_slope_Q14 = (1 << 14) / static_cast(win_length); - } - int16_t win_up_Q14 = 0; - for (size_t i = 0; i < win_length; i++) { - win_up_Q14 += win_slope_Q14; - (*output)[channel_ix][i] = - (win_up_Q14 * (*output)[channel_ix][i] + - ((1 << 14) - win_up_Q14) * expanded[channel_ix][i] + (1 << 13)) >> - 14; - } - RTC_DCHECK_GT(win_up_Q14, - (1 << 14) - 32); // Worst case rouding is a length of 34 + Crossfade(expanded[channel_ix], (*output)[channel_ix], samples_per_ms_); } } else if (last_mode == NetEq::Mode::kRfc3389Cng) { RTC_DCHECK_EQ(output->Channels(), 1); // Not adapted for multi-channel yet. @@ -170,22 +174,9 @@ } // Interpolate the CNG into the new vector. // (NB/WB/SWB32/SWB48 8/16/32/48 samples.) - size_t win_length = samples_per_ms_; - int16_t win_slope_Q14 = default_win_slope_Q14_; - if (win_length > kCngLength) { - win_length = kCngLength; - win_slope_Q14 = (1 << 14) / static_cast(win_length); - } - int16_t win_up_Q14 = 0; - for (size_t i = 0; i < win_length; i++) { - win_up_Q14 += win_slope_Q14; - (*output)[0][i] = - (win_up_Q14 * (*output)[0][i] + - ((1 << 14) - win_up_Q14) * cng_output[i] + (1 << 13)) >> - 14; - } - RTC_DCHECK_GT(win_up_Q14, - (1 << 14) - 32); // Worst case rouding is a length of 34 + AudioVector temp_vector(kCngLength); + temp_vector.OverwriteAt(cng_output, kCngLength, 0); + Crossfade(temp_vector, (*output)[0], samples_per_ms_); } return static_cast(length); diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.h firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.h --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.h 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/neteq/normal.h 2026-05-06 14:54:51.000000000 +0000 @@ -17,7 +17,6 @@ #include "api/neteq/neteq.h" #include "modules/audio_coding/neteq/statistics_calculator.h" #include "rtc_base/checks.h" -#include "rtc_base/numerics/safe_conversions.h" namespace webrtc { @@ -42,8 +41,6 @@ background_noise_(background_noise), expand_(expand), samples_per_ms_(rtc::CheckedDivExact(fs_hz_, 1000)), - default_win_slope_Q14_( - dchecked_cast((1 << 14) / samples_per_ms_)), statistics_(statistics) {} virtual ~Normal() {} @@ -68,7 +65,6 @@ const BackgroundNoise& background_noise_; Expand* expand_; const size_t samples_per_ms_; - const int16_t default_win_slope_Q14_; StatisticsCalculator* const statistics_; }; diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/neteq/normal_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/neteq/normal_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/audio_coding/neteq/normal_unittest.cc 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/audio_coding/neteq/normal_unittest.cc 2026-05-06 14:54:52.000000000 +0000 @@ -146,6 +146,20 @@ EXPECT_CALL(expand, Die()); // Called when `expand` goes out of scope. } +TEST(Normal, LastModeRfc3389CngSmallInput) { + constexpr size_t kChannels = 1; + constexpr size_t kInputFrames = 10; + MockDecoderDatabase db; + Normal normal(/*fs_hz=*/48000, /*decoder_database=*/&db, + /*background_noise=*/BackgroundNoise(kChannels), + /*expand=*/nullptr, /*statistics=*/nullptr); + AudioMultiVector output(kChannels); + std::vector input(kChannels * kInputFrames, 0); + EXPECT_EQ(normal.Process(input.data(), input.size(), NetEq::Mode::kRfc3389Cng, + &output), + static_cast(input.size())); +} + // TODO(hlundin): Write more tests. } // namespace webrtc diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/BUILD.gn firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/BUILD.gn --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/BUILD.gn 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/BUILD.gn 2026-05-06 14:54:53.000000000 +0000 @@ -1046,6 +1046,7 @@ "../../api:create_frame_generator", "../../api:create_videocodec_test_fixture_api", "../../api:frame_generator_api", + "../../api:make_ref_counted", "../../api:mock_video_codec_factory", "../../api:mock_video_decoder", "../../api:mock_video_encoder", diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/av1/BUILD.gn firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/av1/BUILD.gn --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/av1/BUILD.gn 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/av1/BUILD.gn 2026-05-06 14:54:52.000000000 +0000 @@ -99,6 +99,8 @@ "../../../../api:create_frame_generator", "../../../../api:frame_generator_api", "../../../../api:mock_video_encoder", + "../../../../api:make_ref_counted", + "../../../../api:scoped_refptr", "../../../../api/environment", "../../../../api/environment:environment_factory", "../../../../api/units:data_size", diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc 2026-05-06 14:54:53.000000000 +0000 @@ -609,6 +609,13 @@ MaybeRewrapImgWithFormat(AOM_IMG_FMT_I420); auto i420_buffer = mapped_buffer->GetI420(); RTC_DCHECK(i420_buffer); + + // TODO: crbug.com/492213293 - Remove once the root cause is fixed. + if (i420_buffer->StrideU() != i420_buffer->StrideV()) { + RTC_LOG(LS_ERROR) << "Libaom requires the U and V strides to be equal."; + return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE; + } + RTC_CHECK_EQ(i420_buffer->width(), frame_for_encode_->d_w); RTC_CHECK_EQ(i420_buffer->height(), frame_for_encode_->d_h); frame_for_encode_->planes[AOM_PLANE_Y] = diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/av1/libaom_av1_unittest.cc 2026-05-06 14:54:53.000000000 +0000 @@ -20,8 +20,13 @@ #include "api/environment/environment.h" #include "api/environment/environment_factory.h" +#include "api/make_ref_counted.h" +#include "api/scoped_refptr.h" +#include "api/test/mock_video_encoder.h" #include "api/units/data_size.h" #include "api/units/time_delta.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_frame_buffer.h" #include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_encoder.h" #include "modules/video_coding/codecs/av1/dav1d_decoder.h" @@ -163,6 +168,80 @@ EXPECT_EQ(decoder.num_output_frames(), decoder.decoded_frame_ids().size()); } +TEST(LibaomAv1Test, RejectsNativeFramesWithUnequalChromaStrides) { + const Environment env = CreateEnvironment(); + std::unique_ptr encoder = CreateLibaomAv1Encoder(env); + VideoCodec codec_settings = DefaultCodecSettings(); + ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), + WEBRTC_VIDEO_CODEC_OK); + + VideoBitrateAllocation allocation; + allocation.SetBitrate(0, 0, 300000); + encoder->SetRates(VideoEncoder::RateControlParameters( + allocation, codec_settings.maxFramerate)); + + MockEncodedImageCallback callback; + encoder->RegisterEncodeCompleteCallback(&callback); + + class FakeNativeBuffer : public VideoFrameBuffer { + public: + FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} + Type type() const override { return Type::kNative; } + int width() const override { return width_; } + int height() const override { return height_; } + scoped_refptr ToI420() override { + return I420Buffer::Create(width_, height_, width_, (width_ + 1) / 2, + (width_ + 1) / 2 + 1); + } + + private: + int width_; + int height_; + }; + + auto buffer = make_ref_counted(codec_settings.width, + codec_settings.height); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ENCODER_FAILURE, + encoder->Encode(frame, nullptr)); +} + +TEST(LibaomAv1Test, RejectsI420FramesWithUnequalChromaStrides) { + const Environment env = CreateEnvironment(); + std::unique_ptr encoder = CreateLibaomAv1Encoder(env); + VideoCodec codec_settings = DefaultCodecSettings(); + ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()), + WEBRTC_VIDEO_CODEC_OK); + + VideoBitrateAllocation allocation; + allocation.SetBitrate(0, 0, 300000); + encoder->SetRates(VideoEncoder::RateControlParameters( + allocation, codec_settings.maxFramerate)); + + MockEncodedImageCallback callback; + encoder->RegisterEncodeCompleteCallback(&callback); + + auto buffer = I420Buffer::Create( + /*width=*/codec_settings.width, + /*height=*/codec_settings.height, + /*stride_y=*/codec_settings.width, + /*stride_u=*/(codec_settings.width + 1) / 2, + /*stride_v=*/(codec_settings.width + 1) / 2 + 1); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ENCODER_FAILURE, + encoder->Encode(frame, nullptr)); +} + struct LayerId { friend bool operator==(const LayerId& lhs, const LayerId& rhs) { return std::tie(lhs.spatial_id, lhs.temporal_id) == diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc 2026-05-06 14:54:52.000000000 +0000 @@ -429,6 +429,11 @@ << " image to I420. Can't encode frame."; return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE; } + if (frame_buffer->StrideU() != frame_buffer->StrideV()) { + // TODO: crbug.com/chromium:491655161 - Remove once the root cause is fixed. + RTC_LOG(LS_ERROR) << "OpenH264 requires the U and V strides to be equal."; + return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE; + } RTC_CHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 || frame_buffer->type() == VideoFrameBuffer::Type::kI420A); diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/h264/h264_encoder_impl_unittest.cc 2026-05-06 14:54:52.000000000 +0000 @@ -12,6 +12,14 @@ #include "modules/video_coding/codecs/h264/h264_encoder_impl.h" #include "api/environment/environment_factory.h" +#include "api/make_ref_counted.h" +#include "api/scoped_refptr.h" +#include "api/test/create_frame_generator.h" +#include "api/test/frame_generator_interface.h" +#include "api/test/mock_video_encoder.h" +#include "api/video/i420_buffer.h" +#include "api/video/video_frame.h" +#include "api/video/video_frame_buffer.h" #include "api/video_codecs/video_encoder.h" #include "modules/video_coding/include/video_error_codes.h" #include "test/gtest.h" @@ -74,6 +82,68 @@ encoder.PacketizationModeForTesting()); } +TEST(H264EncoderImplTest, RejectsI420FramesWithUnequalChromaStrides) { + H264EncoderImpl encoder(CreateEnvironment(), {}); + VideoCodec codec_settings; + SetDefaultSettings(&codec_settings); + MockEncodedImageCallback callback; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder.InitEncode(&codec_settings, kSettings)); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder.RegisterEncodeCompleteCallback(&callback)); + // Create a VideoFrame where the U and V strides are different. + auto buffer = I420Buffer::Create( + /*width=*/codec_settings.width, + /*height=*/codec_settings.height, + /*stride_y=*/codec_settings.width, + /*stride_u=*/(codec_settings.width + 1) / 2, + /*stride_v=*/(codec_settings.width + 1) / 2 + 1); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ENCODER_FAILURE, encoder.Encode(frame, nullptr)); +} + +TEST(H264EncoderImplTest, RejectsNativeFramesWithUnequalChromaStrides) { + H264EncoderImpl encoder(CreateEnvironment(), {}); + VideoCodec codec_settings; + SetDefaultSettings(&codec_settings); + MockEncodedImageCallback callback; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder.InitEncode(&codec_settings, kSettings)); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder.RegisterEncodeCompleteCallback(&callback)); + + class FakeNativeBuffer : public VideoFrameBuffer { + public: + FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} + Type type() const override { return Type::kNative; } + int width() const override { return width_; } + int height() const override { return height_; } + scoped_refptr ToI420() override { + return I420Buffer::Create(width_, height_, width_, (width_ + 1) / 2, + (width_ + 1) / 2 + 1); + } + + private: + int width_; + int height_; + }; + + auto buffer = make_ref_counted(codec_settings.width, + codec_settings.height); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ENCODER_FAILURE, encoder.Encode(frame, nullptr)); +} + } // anonymous namespace } // namespace webrtc diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc 2026-05-06 14:54:52.000000000 +0000 @@ -1453,6 +1453,13 @@ << " image to I420. Can't encode frame."; return {}; } + + // TODO: crbug.com/492213293 - Remove once the root cause is fixed. + if (converted_buffer->StrideU() != converted_buffer->StrideV()) { + RTC_LOG(LS_ERROR) << "Libvpx requires the U and V strides to be equal."; + return {}; + } + RTC_CHECK(converted_buffer->type() == VideoFrameBuffer::Type::kI420 || converted_buffer->type() == VideoFrameBuffer::Type::kI420A); @@ -1524,6 +1531,21 @@ SetRawImagePlanes(&raw_images_[i], scaled_buffer.get()); prepared_buffers.push_back(scaled_buffer); } + + // TODO: crbug.com/492213293 - Remove once the root cause is fixed. + for (const scoped_refptr& prepared_buffer : + prepared_buffers) { + if (prepared_buffer->type() == VideoFrameBuffer::Type::kI420 || + prepared_buffer->type() == VideoFrameBuffer::Type::kI420A) { + auto i420_buffer = prepared_buffer->GetI420(); + RTC_DCHECK(i420_buffer); + if (i420_buffer->StrideU() != i420_buffer->StrideV()) { + RTC_LOG(LS_ERROR) << "Libvpx requires the U and V strides to be equal."; + return {}; + } + } + } + return prepared_buffers; } diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc 2026-05-06 14:54:53.000000000 +0000 @@ -14,11 +14,13 @@ #include #include "absl/memory/memory.h" +#include "api/make_ref_counted.h" #include "api/environment/environment_factory.h" #include "api/test/create_frame_generator.h" #include "api/test/frame_generator_interface.h" #include "api/test/mock_video_decoder.h" #include "api/test/mock_video_encoder.h" +#include "api/video/i420_buffer.h" #include "api/video_codecs/video_encoder.h" #include "api/video_codecs/vp8_temporal_layers.h" #include "common_video/libyuv/include/webrtc_libyuv.h" @@ -207,6 +209,55 @@ encoder_->Encode(NextInputFrame(), nullptr)); } +TEST_F(TestVp8Impl, RejectsI420FramesWithUnequalChromaStrides) { + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, kSettings)); + + auto buffer = I420Buffer::Create( + /*width=*/kWidth, + /*height=*/kHeight, + /*stride_y=*/kWidth, + /*stride_u=*/(kWidth + 1) / 2, + /*stride_v=*/(kWidth + 1) / 2 + 1); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, encoder_->Encode(frame, nullptr)); +} + +TEST_F(TestVp8Impl, RejectsNativeFramesWithUnequalChromaStrides) { + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, kSettings)); + + class FakeNativeBuffer : public VideoFrameBuffer { + public: + FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} + Type type() const override { return Type::kNative; } + int width() const override { return width_; } + int height() const override { return height_; } + scoped_refptr ToI420() override { + return I420Buffer::Create(width_, height_, width_, (width_ + 1) / 2, + (width_ + 1) / 2 + 1); + } + + private: + int width_; + int height_; + }; + + auto buffer = make_ref_counted(kWidth, kHeight); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, encoder_->Encode(frame, nullptr)); +} + TEST_F(TestVp8Impl, EncodeNv12FrameSimulcast) { EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc 2026-05-06 14:54:52.000000000 +0000 @@ -1186,6 +1186,13 @@ i010_buffer = i010_copy.get(); } } + + // TODO: crbug.com/492213293 - Remove once the root cause is fixed. + if (i010_buffer->StrideU() != i010_buffer->StrideV()) { + RTC_LOG(LS_ERROR) << "Libvpx requires the U and V strides to be equal."; + return WEBRTC_VIDEO_CODEC_ERROR; + } + raw_->planes[VPX_PLANE_Y] = const_cast( reinterpret_cast(i010_buffer->DataY())); raw_->planes[VPX_PLANE_U] = const_cast( @@ -2122,6 +2129,13 @@ MaybeRewrapRawWithFormat(VPX_IMG_FMT_I420); const I420BufferInterface* i420_buffer = mapped_buffer->GetI420(); RTC_DCHECK(i420_buffer); + + // TODO: crbug.com/492213293 - Remove once the root cause is fixed. + if (i420_buffer->StrideU() != i420_buffer->StrideV()) { + RTC_LOG(LS_ERROR) << "Libvpx requires the U and V strides to be equal."; + return {}; + } + raw_->planes[VPX_PLANE_Y] = const_cast(i420_buffer->DataY()); raw_->planes[VPX_PLANE_U] = const_cast(i420_buffer->DataU()); raw_->planes[VPX_PLANE_V] = const_cast(i420_buffer->DataV()); diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc 2026-05-06 14:54:53.000000000 +0000 @@ -9,6 +9,7 @@ */ #include "absl/memory/memory.h" +#include "api/make_ref_counted.h" #include "api/test/create_frame_generator.h" #include "api/test/frame_generator_interface.h" #include "api/test/mock_video_encoder.h" @@ -233,6 +234,55 @@ encoded_frame.PresentationTimestamp()->us()); } +TEST_F(TestVp9Impl, RejectsI420FramesWithUnequalChromaStrides) { + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, kSettings)); + + auto buffer = I420Buffer::Create( + /*width=*/kWidth, + /*height=*/kHeight, + /*stride_y=*/kWidth, + /*stride_u=*/(kWidth + 1) / 2, + /*stride_v=*/(kWidth + 1) / 2 + 1); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, encoder_->Encode(frame, nullptr)); +} + +TEST_F(TestVp9Impl, RejectsNativeFramesWithUnequalChromaStrides) { + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, kSettings)); + + class FakeNativeBuffer : public VideoFrameBuffer { + public: + FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} + Type type() const override { return Type::kNative; } + int width() const override { return width_; } + int height() const override { return height_; } + scoped_refptr ToI420() override { + return I420Buffer::Create(width_, height_, width_, (width_ + 1) / 2, + (width_ + 1) / 2 + 1); + } + + private: + int width_; + int height_; + }; + + auto buffer = make_ref_counted(kWidth, kHeight); + + VideoFrame frame = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rtp_timestamp(0) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, encoder_->Encode(frame, nullptr)); +} + TEST_F(TestVp9Impl, SwitchInputPixelFormatsWithoutReconfigure) { EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(NextInputFrame(), nullptr)); EncodedImage encoded_frame; diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/video_codec_initializer.cc firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/video_codec_initializer.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/modules/video_coding/video_codec_initializer.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/modules/video_coding/video_codec_initializer.cc 2026-05-06 14:54:52.000000000 +0000 @@ -74,8 +74,8 @@ config.legacy_conference_mode; video_codec.SetFrameDropEnabled(config.frame_drop_enabled); - video_codec.numberOfSimulcastStreams = - static_cast(streams.size()); + video_codec.numberOfSimulcastStreams = static_cast( + std::min(streams.size(), static_cast(kMaxSimulcastStreams))); video_codec.minBitrate = streams[0].min_bitrate_bps / 1000; bool codec_active = false; // Active configuration might not be fully copied to `streams` for SVC yet. @@ -97,7 +97,9 @@ int max_framerate = 0; std::optional scalability_mode = streams[0].scalability_mode; - for (size_t i = 0; i < streams.size(); ++i) { + const size_t num_streams = + std::min(streams.size(), static_cast(kMaxSimulcastStreams)); + for (size_t i = 0; i < num_streams; ++i) { SimulcastStream* sim_stream = &video_codec.simulcastStream[i]; RTC_DCHECK_GT(streams[i].width, 0); RTC_DCHECK_GT(streams[i].height, 0); diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/pc/sdp_offer_answer.cc firefox-esr-140.10.2esr/third_party/libwebrtc/pc/sdp_offer_answer.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/pc/sdp_offer_answer.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/pc/sdp_offer_answer.cc 2026-05-06 14:54:52.000000000 +0000 @@ -633,6 +633,12 @@ // This is a remote description, the parameters we are after should appear // as receive streams. for (const auto& alternatives : simulcast.receive_layers()) { + if (result.size() >= kMaxSimulcastStreams) { + RTC_LOG(LS_WARNING) + << "Excessive simulcast layers in remote description. Clamping to " + << kMaxSimulcastStreams; + break; + } RTC_DCHECK(!alternatives.empty()); // There is currently no way to specify or choose from alternatives. // We will always use the first alternative, which is the most preferred. diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc 2026-04-27 16:09:05.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc 2026-05-06 14:54:52.000000000 +0000 @@ -758,6 +758,46 @@ EXPECT_TRUE(pc->SetLocalDescription(std::move(answer))); } +TEST_F(SdpOfferAnswerTest, SimulcastOfferWithExcessiveRidsClamped) { + auto pc = CreatePeerConnection(); + + std::string sdp = + "v=0\r\n" + "o=- 4131505339648218884 3 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=ice-ufrag:zGWFZ+fVXDeN6UoI/136\r\n" + "a=ice-pwd:9AUNgUqRNI5LSIrC1qFD2iTR\r\n" + "a=fingerprint:sha-256 " + "AD:52:52:E0:B1:37:34:21:0E:15:8E:B7:56:56:7B:B4:39:0E:6D:1C:F5:84:A7:EE:" + "B5:27:3E:30:B1:7D:69:42\r\n" + "a=setup:passive\r\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=mid:0\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n" + "a=recvonly\r\n" + "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" + "a=rtpmap:96 VP8/90000\r\n"; + + for (int i = 1; i <= 9; ++i) { + sdp += "a=rid:" + std::to_string(i) + " recv\r\n"; + } + sdp += "a=simulcast:recv 1;2;3;4;5;6;7;8;9\r\n"; + + std::unique_ptr offer = + CreateSessionDescription(SdpType::kOffer, sdp); + EXPECT_TRUE(pc->SetRemoteDescription(std::move(offer))); + + auto transceiver = pc->pc()->GetTransceivers()[0]; + // Verify that the number of send encodings is clamped to 3 + // (kMaxSimulcastStreams) + EXPECT_THAT(transceiver->sender()->GetParameters().encodings, SizeIs(3)); +} + TEST_F(SdpOfferAnswerTest, ExpectAllSsrcsSpecifiedInSsrcGroupFid) { auto pc = CreatePeerConnection(); std::string sdp = diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/BUILD.gn firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/BUILD.gn --- firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/BUILD.gn 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/BUILD.gn 2026-05-06 14:54:52.000000000 +0000 @@ -2043,6 +2043,7 @@ "task_utils:repeating_task", "third_party/base64", "third_party/sigslot", + "//testing/gtest", "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/numeric:bits", diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/strings/string_builder.cc firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/strings/string_builder.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/strings/string_builder.cc 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/strings/string_builder.cc 2026-05-06 14:54:53.000000000 +0000 @@ -24,7 +24,7 @@ SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView buffer) : buffer_(buffer) { buffer_[0] = '\0'; - RTC_DCHECK(IsConsistent()); + RTC_CHECK(IsConsistent()); } SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) { @@ -32,13 +32,13 @@ } SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) { - RTC_DCHECK_LT(size_ + str.length(), buffer_.size()) + RTC_CHECK_LT(size_ + str.length(), buffer_.size()) << "Buffer size was insufficient"; const size_t chars_added = SafeMin(str.length(), buffer_.size() - size_ - 1); memcpy(&buffer_[size_], str.data(), chars_added); size_ += chars_added; buffer_[size_] = '\0'; - RTC_DCHECK(IsConsistent()); + RTC_CHECK(IsConsistent()); return *this; } @@ -98,7 +98,7 @@ if (len >= 0) { const size_t chars_added = SafeMin(len, buffer_.size() - 1 - size_); size_ += chars_added; - RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient"; + RTC_CHECK_EQ(len, chars_added) << "Buffer size was insufficient"; } else { // This should never happen, but we're paranoid, so re-write the // terminator in case vsnprintf() overwrote it. @@ -106,7 +106,7 @@ buffer_[size_] = '\0'; } va_end(args); - RTC_DCHECK(IsConsistent()); + RTC_CHECK(IsConsistent()); return *this; } diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/strings/string_builder.h firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/strings/string_builder.h --- firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/strings/string_builder.h 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/strings/string_builder.h 2026-05-06 14:54:53.000000000 +0000 @@ -148,11 +148,8 @@ size_t size() const { return str_.size(); } - std::string Release() { - std::string ret = std::move(str_); - str_.clear(); - return ret; - } + // Moves out the internal std::string. + std::string Release() { return std::move(str_); } // Allows appending a printf style formatted string. StringBuilder& AppendFormat(const char* fmt, ...) diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc 2026-04-27 16:09:07.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc 2026-05-06 14:54:53.000000000 +0000 @@ -12,7 +12,6 @@ #include -#include "rtc_base/checks.h" #include "test/gmock.h" #include "test/gtest.h" @@ -57,18 +56,13 @@ // These tests are safe to run if we have death test support or if DCHECKs are // off. -#if (GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)) || !RTC_DCHECK_IS_ON +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharP) { char sb_buf[4]; webrtc::SimpleStringBuilder sb(sb_buf); const char* const msg = "This is just too much"; -#if RTC_DCHECK_IS_ON EXPECT_DEATH(sb << msg, ""); -#else - sb << msg; - EXPECT_THAT(sb.str(), ::testing::StrEq("Thi")); -#endif } TEST(SimpleStringBuilderDeathTest, BufferOverrunStdString) { @@ -76,41 +70,21 @@ webrtc::SimpleStringBuilder sb(sb_buf); sb << 12; const std::string msg = "Aw, come on!"; -#if RTC_DCHECK_IS_ON EXPECT_DEATH(sb << msg, ""); -#else - sb << msg; - EXPECT_THAT(sb.str(), ::testing::StrEq("12A")); -#endif } TEST(SimpleStringBuilderDeathTest, BufferOverrunInt) { char sb_buf[4]; webrtc::SimpleStringBuilder sb(sb_buf); constexpr int num = -12345; -#if RTC_DCHECK_IS_ON EXPECT_DEATH(sb << num, ""); -#else - sb << num; - // If we run into the end of the buffer, resonable results are either that - // the append has no effect or that it's truncated at the point where the - // buffer ends. - EXPECT_THAT(sb.str(), - ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("-12"))); -#endif } TEST(SimpleStringBuilderDeathTest, BufferOverrunDouble) { char sb_buf[5]; webrtc::SimpleStringBuilder sb(sb_buf); constexpr double num = 123.456; -#if RTC_DCHECK_IS_ON EXPECT_DEATH(sb << num, ""); -#else - sb << num; - EXPECT_THAT(sb.str(), - ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("123."))); -#endif } TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharPAlreadyFull) { @@ -118,12 +92,7 @@ webrtc::SimpleStringBuilder sb(sb_buf); sb << 123; const char* const msg = "This is just too much"; -#if RTC_DCHECK_IS_ON EXPECT_DEATH(sb << msg, ""); -#else - sb << msg; - EXPECT_THAT(sb.str(), ::testing::StrEq("123")); -#endif } TEST(SimpleStringBuilderDeathTest, BufferOverrunIntAlreadyFull) { @@ -131,12 +100,7 @@ webrtc::SimpleStringBuilder sb(sb_buf); sb << "xyz"; constexpr int num = -12345; -#if RTC_DCHECK_IS_ON EXPECT_DEATH(sb << num, ""); -#else - sb << num; - EXPECT_THAT(sb.str(), ::testing::StrEq("xyz")); -#endif } #endif diff -Nru firefox-esr-140.10.1esr/third_party/libwebrtc/video/video_receive_stream2.cc firefox-esr-140.10.2esr/third_party/libwebrtc/video/video_receive_stream2.cc --- firefox-esr-140.10.1esr/third_party/libwebrtc/video/video_receive_stream2.cc 2026-04-27 16:09:06.000000000 +0000 +++ firefox-esr-140.10.2esr/third_party/libwebrtc/video/video_receive_stream2.cc 2026-05-06 14:54:52.000000000 +0000 @@ -540,8 +540,7 @@ // dumped video, since it's developers-only feature for debugging. absl::c_replace(decoded_output_file, ';', '/'); if (!decoded_output_file.empty()) { - char filename_buffer[256]; - SimpleStringBuilder ssb(filename_buffer); + StringBuilder ssb; ssb << decoded_output_file << "/webrtc_receive_stream_" << remote_ssrc() << "-" << rtc::TimeMicros() << ".ivf"; video_decoder = CreateFrameDumpingDecoderWrapper( diff -Nru firefox-esr-140.10.1esr/toolkit/components/telemetry/tests/marionette/tests/client/test_shutdown_pings_succeed.py firefox-esr-140.10.2esr/toolkit/components/telemetry/tests/marionette/tests/client/test_shutdown_pings_succeed.py --- firefox-esr-140.10.1esr/toolkit/components/telemetry/tests/marionette/tests/client/test_shutdown_pings_succeed.py 2026-04-27 16:09:09.000000000 +0000 +++ firefox-esr-140.10.2esr/toolkit/components/telemetry/tests/marionette/tests/client/test_shutdown_pings_succeed.py 2026-05-06 14:54:55.000000000 +0000 @@ -38,11 +38,13 @@ "new-profile": pingsender_version, } - # We don't need the browser after this, but the harness expects a - # running browser to clean up, so we `restart_browser` rather than - # `quit_browser`. + # You'd think we could just `quit_browser`, but the test needs a second + # session for the "main" ping to be sent and the harness needs it for + # cleanup, so we could `restart_browser`, but in bug 2012689 we found + # that Windows opt could restart the browser faster than invoking + # pingsender... so we `quit_browser` and then `start_browser`. pings = self.wait_for_pings( - self.restart_browser, + lambda: self.quit_browser() and self.start_browser(), lambda p: p["type"] in ping_types.keys(), len(ping_types), ) diff -Nru firefox-esr-140.10.1esr/widget/windows/nsWindowGfx.cpp firefox-esr-140.10.2esr/widget/windows/nsWindowGfx.cpp --- firefox-esr-140.10.1esr/widget/windows/nsWindowGfx.cpp 2026-04-27 16:09:09.000000000 +0000 +++ firefox-esr-140.10.2esr/widget/windows/nsWindowGfx.cpp 2026-05-06 14:54:56.000000000 +0000 @@ -167,7 +167,7 @@ return true; } - WindowRenderer* renderer = GetWindowRenderer(); + RefPtr renderer = GetWindowRenderer(); KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor(); WebRenderLayerManager* layerManager = renderer->AsWebRender(); const bool isFallback =