From f596e35554ac5dceac40641b5be5d0f8f4467653 Mon Sep 17 00:00:00 2001 From: "electron-roller[bot]" <84116207+electron-roller[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 12:38:31 -0400 Subject: [PATCH] chore: bump chromium to 146.0.7680.208 (41-x-y) (#51089) * chore: bump chromium in DEPS to 146.0.7680.201 * chore: update patches * chore: bump chromium in DEPS to 146.0.7680.208 * chore: update patches * chore: update patches --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: John Kleinschmidt Co-authored-by: Charles Kerr --- DEPS | 2 +- patches/chromium/.patches | 5 - .../chromium/cherry-pick-23865499a86a.patch | 224 ------ .../chromium/cherry-pick-8b08fb7c9dce.patch | 67 -- .../chromium/cherry-pick-bb8d4c29dfdb.patch | 94 --- .../chromium/cherry-pick-be87466afecb.patch | 224 ------ .../chromium/cherry-pick-cve-2026-6920.patch | 10 +- .../chromium/cherry-pick-eeb3e031eb89.patch | 373 ---------- ..._avoid_private_macos_api_usage.patch.patch | 4 +- patches/config.json | 1 - patches/libaom/.patches | 2 - patches/libaom/cherry-pick-4369bd1258dc.patch | 24 - patches/libaom/cherry-pick-a047955845e5.patch | 187 ----- patches/pdfium/.patches | 2 - patches/pdfium/cherry-pick-bce2e6728279.patch | 36 - patches/pdfium/cherry-pick-ca8a943c247c.patch | 70 -- patches/skia/.patches | 1 - patches/skia/cherry-pick-0566b2f5f0d1.patch | 651 ------------------ 18 files changed, 8 insertions(+), 1969 deletions(-) delete mode 100644 patches/chromium/cherry-pick-23865499a86a.patch delete mode 100644 patches/chromium/cherry-pick-8b08fb7c9dce.patch delete mode 100644 patches/chromium/cherry-pick-bb8d4c29dfdb.patch delete mode 100644 patches/chromium/cherry-pick-be87466afecb.patch delete mode 100644 patches/chromium/cherry-pick-eeb3e031eb89.patch delete mode 100644 patches/libaom/cherry-pick-4369bd1258dc.patch delete mode 100644 patches/libaom/cherry-pick-a047955845e5.patch delete mode 100644 patches/pdfium/.patches delete mode 100644 patches/pdfium/cherry-pick-bce2e6728279.patch delete mode 100644 patches/pdfium/cherry-pick-ca8a943c247c.patch delete mode 100644 patches/skia/cherry-pick-0566b2f5f0d1.patch diff --git a/DEPS b/DEPS index d5096b66b1..2a21653b67 100644 --- a/DEPS +++ b/DEPS @@ -2,7 +2,7 @@ gclient_gn_args_from = 'src' vars = { 'chromium_version': - '146.0.7680.188', + '146.0.7680.208', 'node_version': 'v24.15.0', 'nan_version': diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 2082f22fe7..26a1c0249d 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -157,19 +157,14 @@ fix_initialize_com_on_desktopmedialistcapturethread_on_windows.patch fix_use_fresh_lazynow_for_onendworkitemimpl_after_didruntask.patch cherry-pick-4073d491fb55.patch cherry-pick-8c1ead5a699f.patch -cherry-pick-8b08fb7c9dce.patch -cherry-pick-be87466afecb.patch cherry-pick-c215f8e6f049.patch cherry-pick-a6357144e7bf.patch cherry-pick-41bfbc009df8.patch cherry-pick-4002a66778d2.patch -cherry-pick-23865499a86a.patch cherry-pick-c81f01b469c4.patch cherry-pick-1b69067db7d2.patch cherry-pick-d513cd2fe668.patch -cherry-pick-bb8d4c29dfdb.patch cherry-pick-847b11ad2fa3.patch -cherry-pick-eeb3e031eb89.patch cherry-pick-fccaeb9e0967.patch cherry-pick-d141d62357df.patch cherry-pick-c75f63de7188.patch diff --git a/patches/chromium/cherry-pick-23865499a86a.patch b/patches/chromium/cherry-pick-23865499a86a.patch deleted file mode 100644 index c496ca0d59..0000000000 --- a/patches/chromium/cherry-pick-23865499a86a.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Fergal Daly -Date: Sun, 12 Apr 2026 20:37:39 -0700 -Subject: [M146] Fix UAF in FileSystemAccessChangeSource. - -Original change's description: -> Fix UAF in FileSystemAccessChangeSource. -> -> `DidInitialize` calls any outstanding initialization callbacks but a -> callback can delete this. The code guards against this in its access -> of `initialization_callbacks_` but not `initialization_result_`. -> -> This fix keeps a copy of the result on the stack. -> -> This also adds a test which fails with ASAN before the fix is applied -> and passes after. -> -> The basic test code was written by Gemini. -> -> Fixed: 497880137 -> Change-Id: I046831db23cb4b8e41964910e2aede9b1be0db7f -> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7728464 -> Auto-Submit: Fergal Daly -> Reviewed-by: Ming-Ying Chung -> Commit-Queue: Ming-Ying Chung -> Cr-Commit-Position: refs/heads/main@{#1610499} - -(cherry picked from commit c0390bcd64ba1fd6594fbc9f6246a1649662d683) - -Bug: 500247135,497880137 -Change-Id: I046831db23cb4b8e41964910e2aede9b1be0db7f -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7754020 -Commit-Queue: Rubber Stamper -Auto-Submit: Chrome Cherry Picker -Bot-Commit: Rubber Stamper -Cr-Commit-Position: refs/branch-heads/7680@{#3929} -Cr-Branched-From: 76b7d80e5cda23fe6537eed26d68c92e995c7f39-refs/heads/main@{#1582197} - -diff --git a/content/browser/file_system_access/file_system_access_change_source.cc b/content/browser/file_system_access/file_system_access_change_source.cc -index 566dc1ea40b43a54b33d70e82a20ff5695b57b5e..48bd867a9d3d140eaf515ea7bc1613231f7e79e9 100644 ---- a/content/browser/file_system_access/file_system_access_change_source.cc -+++ b/content/browser/file_system_access/file_system_access_change_source.cc -@@ -71,13 +71,14 @@ void FileSystemAccessChangeSource::DidInitialize( - CHECK(!initialization_result_.has_value()); - CHECK(!initialization_callbacks_.empty()); - -- initialization_result_ = std::move(result); -+ // The callbacks may cause |this| to be deleted, so we should only use -+ // stack-based objects below. -+ initialization_result_ = result->Clone(); - -- // Move the callbacks to the stack since they may cause |this| to be deleted. - auto initialization_callbacks = std::move(initialization_callbacks_); - initialization_callbacks_.clear(); - for (auto& callback : initialization_callbacks) { -- std::move(callback).Run(initialization_result_->Clone()); -+ std::move(callback).Run(result->Clone()); - } - } - -diff --git a/content/browser/file_system_access/file_system_access_change_source_unittest.cc b/content/browser/file_system_access/file_system_access_change_source_unittest.cc -new file mode 100644 -index 0000000000000000000000000000000000000000..b0f15909bebda29fc2ec689a6d3b15d797dcc722 ---- /dev/null -+++ b/content/browser/file_system_access/file_system_access_change_source_unittest.cc -@@ -0,0 +1,146 @@ -+// Copyright 2026 The Chromium Authors -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#include "content/browser/file_system_access/file_system_access_change_source.h" -+ -+#include "base/files/scoped_temp_dir.h" -+#include "base/functional/bind.h" -+#include "base/memory/scoped_refptr.h" -+#include "base/task/sequenced_task_runner.h" -+#include "base/test/task_environment.h" -+#include "base/test/test_future.h" -+#include "content/browser/file_system_access/file_system_access_watch_scope.h" -+#include "storage/browser/file_system/file_system_context.h" -+#include "storage/browser/file_system/file_system_url.h" -+#include "storage/browser/quota/quota_manager_proxy.h" -+#include "storage/browser/test/test_file_system_context.h" -+#include "testing/gmock/include/gmock/gmock.h" -+#include "testing/gtest/include/gtest/gtest.h" -+#include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom.h" -+ -+namespace content { -+ -+namespace { -+ -+class MockRawChangeObserver -+ : public FileSystemAccessChangeSource::RawChangeObserver { -+ public: -+ MOCK_METHOD(void, -+ OnRawChange, -+ (const storage::FileSystemURL& changed_url, -+ bool error, -+ const FileSystemAccessChangeSource::ChangeInfo& change_info, -+ const FileSystemAccessWatchScope& scope), -+ (override)); -+ MOCK_METHOD(void, -+ OnUsageChange, -+ (size_t old_usage, -+ size_t new_usage, -+ const FileSystemAccessWatchScope& scope), -+ (override)); -+ MOCK_METHOD(void, -+ OnSourceBeingDestroyed, -+ (FileSystemAccessChangeSource * source), -+ (override)); -+}; -+ -+class FakeChangeSource : public FileSystemAccessChangeSource { -+ public: -+ FakeChangeSource( -+ FileSystemAccessWatchScope scope, -+ scoped_refptr file_system_context) -+ : FileSystemAccessChangeSource(std::move(scope), -+ std::move(file_system_context)) {} -+ ~FakeChangeSource() override = default; -+ -+ // FileSystemAccessChangeSource: -+ void Initialize( -+ base::OnceCallback -+ on_source_initialized) override { -+ base::SequencedTaskRunner::GetCurrentDefault()->PostTask( -+ FROM_HERE, base::BindOnce(std::move(on_source_initialized), -+ blink::mojom::FileSystemAccessError::New( -+ blink::mojom::FileSystemAccessStatus::kOk, -+ base::File::FILE_OK, ""))); -+ } -+ -+ void Signal(const storage::FileSystemURL& changed_url, -+ bool error = false, -+ ChangeInfo change_info = ChangeInfo()) { -+ NotifyOfChange(changed_url, error, change_info); -+ } -+}; -+ -+} // namespace -+ -+class FileSystemAccessChangeSourceTest : public testing::Test { -+ public: -+ FileSystemAccessChangeSourceTest() -+ : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {} -+ -+ void SetUp() override { -+ ASSERT_TRUE(dir_.CreateUniqueTempDir()); -+ file_system_context_ = storage::CreateFileSystemContextForTesting( -+ /*quota_manager_proxy=*/nullptr, dir_.GetPath()); -+ } -+ -+ protected: -+ base::test::TaskEnvironment task_environment_; -+ base::ScopedTempDir dir_; -+ scoped_refptr file_system_context_; -+}; -+ -+TEST_F(FileSystemAccessChangeSourceTest, CreateAndInitialize) { -+ auto file_path = dir_.GetPath().AppendASCII("file"); -+ auto file_url = file_system_context_->CreateCrackedFileSystemURL( -+ blink::StorageKey(), storage::kFileSystemTypeLocal, file_path); -+ -+ auto scope = FileSystemAccessWatchScope::GetScopeForFileWatch(file_url); -+ FakeChangeSource source(scope, file_system_context_); -+ -+ base::test::TestFuture future; -+ source.EnsureInitialized(future.GetCallback()); -+ EXPECT_EQ(future.Get()->status, blink::mojom::FileSystemAccessStatus::kOk); -+} -+ -+TEST_F(FileSystemAccessChangeSourceTest, NotifyOfChange) { -+ auto file_path = dir_.GetPath().AppendASCII("file"); -+ auto file_url = file_system_context_->CreateCrackedFileSystemURL( -+ blink::StorageKey(), storage::kFileSystemTypeLocal, file_path); -+ -+ auto scope = FileSystemAccessWatchScope::GetScopeForFileWatch(file_url); -+ FakeChangeSource source(scope, file_system_context_); -+ -+ MockRawChangeObserver observer; -+ source.AddObserver(&observer); -+ -+ EXPECT_CALL(observer, OnRawChange(testing::Eq(file_url), testing::IsFalse(), -+ testing::_, testing::Eq(scope))); -+ source.Signal(file_url); -+ -+ source.RemoveObserver(&observer); -+} -+ -+// A callback passed to `EnsureInitialized` may result in `this` being -+// destroyed. This tests that `DidInitialize` (which calls the callbacks) is -+// robust to that situation. See https://crbug.com/497880137. -+TEST_F(FileSystemAccessChangeSourceTest, TestDestroyFromInitializeCallback) { -+ auto file_path = dir_.GetPath().AppendASCII("file"); -+ auto file_url = file_system_context_->CreateCrackedFileSystemURL( -+ blink::StorageKey(), storage::kFileSystemTypeLocal, file_path); -+ -+ auto scope = FileSystemAccessWatchScope::GetScopeForFileWatch(file_url); -+ FakeChangeSource* source = new FakeChangeSource(scope, file_system_context_); -+ -+ source->EnsureInitialized(base::BindOnce( -+ [](FakeChangeSource* source, blink::mojom::FileSystemAccessErrorPtr) { -+ delete source; -+ }, -+ base::Unretained(source))); -+ base::test::TestFuture future; -+ source->EnsureInitialized(future.GetCallback()); -+ EXPECT_EQ(future.Get()->status, blink::mojom::FileSystemAccessStatus::kOk); -+} -+ -+} // namespace content -diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn -index 07cbf495717714d71d977a8820e08050c3062526..f5d72a89c7229bf8e897c90660feca482ac82594 100644 ---- a/content/test/BUILD.gn -+++ b/content/test/BUILD.gn -@@ -2656,6 +2656,7 @@ test("content_unittests") { - "../browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc", - "../browser/file_system/browser_file_system_helper_unittest.cc", - "../browser/file_system/file_system_operation_runner_unittest.cc", -+ "../browser/file_system_access/file_system_access_change_source_unittest.cc", - "../browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc", - "../browser/file_system_access/file_system_access_file_handle_impl_unittest.cc", - "../browser/file_system_access/file_system_access_file_modification_host_impl_unittest.cc", diff --git a/patches/chromium/cherry-pick-8b08fb7c9dce.patch b/patches/chromium/cherry-pick-8b08fb7c9dce.patch deleted file mode 100644 index 4eeaf5f0a7..0000000000 --- a/patches/chromium/cherry-pick-8b08fb7c9dce.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: p0-tato -Date: Tue, 14 Apr 2026 13:14:30 -0700 -Subject: [M146] Fix dangling pointers in OpenXrSpatialFrameworkManager - -Original change's description: -> Fix dangling pointers in OpenXrSpatialFrameworkManager -> -> Pointers to vector elements were collected during emplace_back, -> which invalidates them on reallocation. Split into two loops -> and reserve the correct capacity. -> -> Bug: 497724498 -> Change-Id: I204534bc1bd1522fe03db86f03c2c3e0d285631c -> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7735242 -> Commit-Queue: Brian Sheedy -> Reviewed-by: Brian Sheedy -> Reviewed-by: Brandon Jones -> Cr-Commit-Position: refs/heads/main@{#1613990} - -(cherry picked from commit b173791bf4026a6bb43124f7c5f46cfa4539c014) - -Bug: 502440265,497724498 -Change-Id: I204534bc1bd1522fe03db86f03c2c3e0d285631c -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7759844 -Auto-Submit: chrome-cherry-picker@chops-service-accounts.iam.gserviceaccount.com -Bot-Commit: rubber-stamper@appspot.gserviceaccount.com -Commit-Queue: rubber-stamper@appspot.gserviceaccount.com -Cr-Commit-Position: refs/branch-heads/7680@{#3944} -Cr-Branched-From: 76b7d80e5cda23fe6537eed26d68c92e995c7f39-refs/heads/main@{#1582197} - -diff --git a/AUTHORS b/AUTHORS -index 7cc777b399ab46f88b6b1809bf6fd0cb22170694..505480b09c1d41b1facf4e2b165bad86b1815127 100644 ---- a/AUTHORS -+++ b/AUTHORS -@@ -729,6 +729,7 @@ Jihoon Chung - Jihun Brent Kim - Jihwan Marc Kim - Jihye Hyun -+Jihyeon Jeong - Jihyeon Lee - Jim Wu - Jin Yang -diff --git a/device/vr/openxr/openxr_spatial_framework_manager.cc b/device/vr/openxr/openxr_spatial_framework_manager.cc -index 520f25230c427bf775333910530d1ad841f3ad71..5c93d694aa5a2259c683f1d521611046293195a2 100644 ---- a/device/vr/openxr/openxr_spatial_framework_manager.cc -+++ b/device/vr/openxr/openxr_spatial_framework_manager.cc -@@ -71,12 +71,15 @@ OpenXrSpatialFrameworkManager::OpenXrSpatialFrameworkManager( - // to help abstract some of the details of creating the child structs, even - // though at present we only have a configuration base. - std::vector capability_configs; -- std::vector -- capability_config_ptrs; -+ capability_configs.reserve(capability_configuration.size()); - for (auto& [capability, components] : capability_configuration) { - capability_configs.emplace_back(capability, components); -- capability_config_ptrs.push_back( -- capability_configs.back().GetAsBaseHeader()); -+ } -+ -+ std::vector -+ capability_config_ptrs; -+ for (auto& config : capability_configs) { -+ capability_config_ptrs.push_back(config.GetAsBaseHeader()); - } - - XrSpatialContextCreateInfoEXT create_info = { diff --git a/patches/chromium/cherry-pick-bb8d4c29dfdb.patch b/patches/chromium/cherry-pick-bb8d4c29dfdb.patch deleted file mode 100644 index 633cbf1a33..0000000000 --- a/patches/chromium/cherry-pick-bb8d4c29dfdb.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sunny Sachanandani -Date: Fri, 10 Apr 2026 23:37:43 -0700 -Subject: [M146] [gpu] Fix OOB write due to unvalidated get_offset - -Original change's description: -> [gpu] Fix OOB write due to unvalidated get_offset -> -> A compromised GPU process can provide an invalid get_offset to the -> CommandBufferHelper (e.g., via shared memory). This offset is used to -> calculate available space and could lead to out-of-bounds writes in the -> Browser process if not validated. -> -> This change adds a bounds check in -> CommandBufferHelper::UpdateCachedState to ensure that the cached -> get_offset is within the valid range [0, total_entry_count_]. If an -> invalid offset is detected, it forces a context loss, frees the ring -> buffer, and marks the helper as unusable, preventing further operations. -> -> Bug: 498782145 -> Test: CommandBufferHelperTest.* -> Change-Id: I8c64e546ecdc90a5a22d15e57ff762a86a6a6964 -> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7739951 -> Reviewed-by: Vasiliy Telezhnikov -> Auto-Submit: Sunny Sachanandani -> Commit-Queue: Sunny Sachanandani -> Cr-Commit-Position: refs/heads/main@{#1611853} - -(cherry picked from commit dc5e20c4c055d6952854a566d520211c6d505f74) - -Bug: 498782145 -Fixed: 500956607 -Change-Id: Ia726612e0a930ee79460fbd7d795afa4d94e2a7b -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7745786 -Reviewed-by: Vasiliy Telezhnikov -Auto-Submit: Sunny Sachanandani -Bot-Commit: Rubber Stamper -Commit-Queue: Sunny Sachanandani -Cr-Commit-Position: refs/branch-heads/7680@{#3919} -Cr-Branched-From: 76b7d80e5cda23fe6537eed26d68c92e995c7f39-refs/heads/main@{#1582197} - -diff --git a/gpu/command_buffer/client/cmd_buffer_helper.cc b/gpu/command_buffer/client/cmd_buffer_helper.cc -index ccda45b133c6a9f2ee60ccc8900bd4a4ce328394..5aea0c81b29b3507099f399c374f3cb372a3100e 100644 ---- a/gpu/command_buffer/client/cmd_buffer_helper.cc -+++ b/gpu/command_buffer/client/cmd_buffer_helper.cc -@@ -158,6 +158,17 @@ void CommandBufferHelper::UpdateCachedState(const CommandBuffer::State& state) { - service_on_old_buffer_ = - (state.set_get_buffer_count != set_get_buffer_count_); - cached_get_offset_ = service_on_old_buffer_ ? 0 : state.get_offset; -+ -+ if (!service_on_old_buffer_ && -+ (cached_get_offset_ < 0 || cached_get_offset_ > total_entry_count_)) { -+ command_buffer_->ForceLostContext(error::kGuilty); -+ FreeRingBuffer(); -+ usable_ = false; -+ context_lost_ = true; -+ cached_get_offset_ = 0; // Safe fallback -+ return; -+ } -+ - cached_last_token_read_ = state.token; - // Don't transition from a lost context to a working context. - context_lost_ |= error::IsError(state.error); -diff --git a/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/gpu/command_buffer/client/cmd_buffer_helper_test.cc -index 1b9254d318ae770ca980d2fed1399a69438afa10..009a87e8bf7a3475f63cd51206868dec187f5e06 100644 ---- a/gpu/command_buffer/client/cmd_buffer_helper_test.cc -+++ b/gpu/command_buffer/client/cmd_buffer_helper_test.cc -@@ -67,6 +67,8 @@ class CommandBufferHelperTest : public testing::Test { - return helper_->immediate_entry_count_; - } - -+ int32_t TotalEntryCount() const { return helper_->total_entry_count_; } -+ - // Adds a command to the buffer through the helper, while adding it as an - // expected call on the API mock. - void AddCommandWithExpect(error::Error _return, -@@ -655,6 +657,17 @@ TEST_F(CommandBufferHelperTest, IsContextLost) { - EXPECT_TRUE(helper_->IsContextLost()); - } - -+TEST_F(CommandBufferHelperTest, TestInvalidGetOffset) { -+ EXPECT_FALSE(helper_->IsContextLost()); -+ EXPECT_TRUE(helper_->usable()); -+ -+ command_buffer_->SetGetOffsetForTest(TotalEntryCount() + 1); -+ helper_->RefreshCachedToken(); // calls UpdateCachedState internally. -+ -+ EXPECT_TRUE(helper_->IsContextLost()); -+ EXPECT_FALSE(helper_->usable()); -+} -+ - // Checks helper's 'flush generation' updates. - TEST_F(CommandBufferHelperTest, TestFlushGeneration) { - // Explicit flushing only. diff --git a/patches/chromium/cherry-pick-be87466afecb.patch b/patches/chromium/cherry-pick-be87466afecb.patch deleted file mode 100644 index 9f0c2ea532..0000000000 --- a/patches/chromium/cherry-pick-be87466afecb.patch +++ /dev/null @@ -1,224 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jonathan Ross -Date: Wed, 8 Apr 2026 17:15:45 -0700 -Subject: gl: Make DCOMPSurfaceRegistry thread-safe - -DCOMPSurfaceRegistry is accessed from both the GPU IO thread (via -GpuServiceImpl) and the GPU main scheduler thread (via DCOMPTexture). -The underlying base::flat_map is not thread-safe, leading to potential -container corruption and crashes (UAF, BOf) during concurrent access. - -This CL adds a base::Lock to protect all accesses to the map and -includes a new multi-threaded stress test to verify the fix. - -Bug: 493315759 -Change-Id: Ibb7ef5e602f222410fde06a61fb3f5e571e7a70f -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7737061 -Reviewed-by: Sunny Sachanandani -Commit-Queue: Jonathan Ross -Cr-Commit-Position: refs/heads/main@{#1611867} - -diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn -index 3584b693370b5199456608a26ceb763f6e9c3446..1cb66199a0b8adf2035a05fecc411c67180f7e80 100644 ---- a/ui/gl/BUILD.gn -+++ b/ui/gl/BUILD.gn -@@ -552,6 +552,7 @@ test("gl_unittests") { - if (is_win) { - sources += [ - "dcomp_presenter_unittest.cc", -+ "dcomp_surface_registry_unittest.cc", - "delegated_ink_point_renderer_gpu_unittest.cc", - "gl_fence_win_unittest.cc", - "hdr_metadata_helper_win_unittest.cc", -diff --git a/ui/gl/dcomp_surface_registry.cc b/ui/gl/dcomp_surface_registry.cc -index 352cc298b9ea97361ae2a7d668b7d7e9eb455cd5..410f76f8980438abae32b6c89e7083ae48cf1699 100644 ---- a/ui/gl/dcomp_surface_registry.cc -+++ b/ui/gl/dcomp_surface_registry.cc -@@ -3,8 +3,11 @@ - // found in the LICENSE file. - - #include "ui/gl/dcomp_surface_registry.h" -+ -+#include "base/check.h" - #include "base/logging.h" - #include "base/no_destructor.h" -+#include "base/synchronization/lock.h" - - namespace gl { - -@@ -20,8 +23,11 @@ base::UnguessableToken DCOMPSurfaceRegistry::RegisterDCOMPSurfaceHandle( - base::win::ScopedHandle surface) { - DVLOG(1) << __func__; - base::UnguessableToken token = base::UnguessableToken::Create(); -- DCHECK(surface_handle_map_.find(token) == surface_handle_map_.end()); -- surface_handle_map_[token] = std::move(surface); -+ { -+ base::AutoLock lock(lock_); -+ DCHECK(surface_handle_map_.find(token) == surface_handle_map_.end()); -+ surface_handle_map_[token] = std::move(surface); -+ } - DVLOG(1) << __func__ << ": Surface handle registered with token " << token; - return token; - } -@@ -29,12 +35,14 @@ base::UnguessableToken DCOMPSurfaceRegistry::RegisterDCOMPSurfaceHandle( - void DCOMPSurfaceRegistry::UnregisterDCOMPSurfaceHandle( - const base::UnguessableToken& token) { - DVLOG(1) << __func__; -+ base::AutoLock lock(lock_); - surface_handle_map_.erase(token); - } - - base::win::ScopedHandle DCOMPSurfaceRegistry::TakeDCOMPSurfaceHandle( - const base::UnguessableToken& token) { - DVLOG(1) << __func__; -+ base::AutoLock lock(lock_); - auto surface_iter = surface_handle_map_.find(token); - if (surface_iter != surface_handle_map_.end()) { - // Take ownership. -diff --git a/ui/gl/dcomp_surface_registry.h b/ui/gl/dcomp_surface_registry.h -index 803a3cc6398f0777504063118920998869086d7f..7cd9fdbfe8669bc97d4b664fdb29573ec2ea26de 100644 ---- a/ui/gl/dcomp_surface_registry.h -+++ b/ui/gl/dcomp_surface_registry.h -@@ -7,6 +7,7 @@ - - #include "base/containers/flat_map.h" - #include "base/no_destructor.h" -+#include "base/synchronization/lock.h" - #include "base/unguessable_token.h" - #include "base/win/scoped_handle.h" - #include "ui/gl/gl_export.h" -@@ -44,7 +45,9 @@ class GL_EXPORT DCOMPSurfaceRegistry { - ~DCOMPSurfaceRegistry(); - - base::flat_map -- surface_handle_map_; -+ surface_handle_map_ GUARDED_BY(lock_); -+ -+ base::Lock lock_; - }; - - } // namespace gl -diff --git a/ui/gl/dcomp_surface_registry_unittest.cc b/ui/gl/dcomp_surface_registry_unittest.cc -new file mode 100644 -index 0000000000000000000000000000000000000000..595e2388e9f50df33214359ecef0c135d94610b8 ---- /dev/null -+++ b/ui/gl/dcomp_surface_registry_unittest.cc -@@ -0,0 +1,118 @@ -+// Copyright 2026 The Chromium Authors -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#include "ui/gl/dcomp_surface_registry.h" -+ -+#include -+ -+#include -+#include -+#include -+ -+#include "base/memory/raw_ptr.h" -+#include "base/synchronization/lock.h" -+#include "base/unguessable_token.h" -+#include "base/win/scoped_handle.h" -+#include "testing/gtest/include/gtest/gtest.h" -+ -+namespace gl { -+ -+namespace { -+ -+class DCOMPSurfaceRegistryTest : public testing::Test { -+ public: -+ void SetUp() override { registry_ = DCOMPSurfaceRegistry::GetInstance(); } -+ -+ protected: -+ raw_ptr registry_; -+}; -+ -+} // namespace -+ -+// Stress test for concurrent access to DCOMPSurfaceRegistry using the -+// barrier pattern to ensure TSAN consistently catches data races. -+// -+// Without proper synchronization (e.g., base::Lock), this test would likely -+// fail in the following ways: -+// 1. Memory Corruption (UAF/HeapBOf): base::flat_map uses a contiguous -+// std::vector. If one thread triggers a reallocation during an insertion -+// while another thread is searching or erasing, the latter will hold an -+// invalidated iterator or pointer. -+// 2. Container Inconsistency: Concurrent insertions and erasures can leave -+// the map in an unsorted or corrupted state, leading to failed lookups -+// for valid tokens. -+// 3. Sanitizer Triggers: ASan would detect container-overflow or -+// heap-use-after-free, and TSan would flag a data race. -+TEST_F(DCOMPSurfaceRegistryTest, ConcurrentRegisterAndTake) { -+ const int kOpsPerThread = 100; -+ -+ std::vector tokens; -+ base::Lock tokens_lock; -+ -+ std::atomic start_flag{false}; -+ std::atomic threads_ready{0}; -+ -+ auto register_worker = [&]() { -+ threads_ready++; -+ while (!start_flag.load(std::memory_order_acquire)) { -+ std::this_thread::yield(); -+ } -+ -+ for (int i = 0; i < kOpsPerThread; ++i) { -+ base::win::ScopedHandle handle( -+ ::CreateEvent(nullptr, FALSE, FALSE, nullptr)); -+ base::UnguessableToken token = -+ registry_->RegisterDCOMPSurfaceHandle(std::move(handle)); -+ { -+ base::AutoLock lock(tokens_lock); -+ tokens.push_back(token); -+ } -+ } -+ }; -+ -+ auto take_worker = [&]() { -+ threads_ready++; -+ while (!start_flag.load(std::memory_order_acquire)) { -+ std::this_thread::yield(); -+ } -+ -+ int taken = 0; -+ while (taken < kOpsPerThread) { -+ base::UnguessableToken token; -+ { -+ base::AutoLock lock(tokens_lock); -+ if (!tokens.empty()) { -+ token = tokens.back(); -+ tokens.pop_back(); -+ } -+ } -+ if (!token.is_empty()) { -+ base::win::ScopedHandle handle = -+ registry_->TakeDCOMPSurfaceHandle(token); -+ taken++; -+ } else { -+ std::this_thread::yield(); -+ } -+ } -+ }; -+ -+ // With the barrier pattern, two threads are sufficient to trigger -+ // the race condition for TSAN. -+ std::thread t1(register_worker); -+ std::thread t2(take_worker); -+ -+ // Wait until both threads are ready at the starting line. -+ while (threads_ready.load(std::memory_order_relaxed) < 2) { -+ std::this_thread::yield(); -+ } -+ -+ // Signal the staring flag to allow both threads to race from the initialized -+ // state. -+ start_flag.store(true, std::memory_order_release); -+ -+ t1.join(); -+ t2.join(); -+} -+ -+} // namespace gl diff --git a/patches/chromium/cherry-pick-cve-2026-6920.patch b/patches/chromium/cherry-pick-cve-2026-6920.patch index 42cc13f04a..d52adae42b 100644 --- a/patches/chromium/cherry-pick-cve-2026-6920.patch +++ b/patches/chromium/cherry-pick-cve-2026-6920.patch @@ -21,10 +21,10 @@ Cr-Commit-Position: refs/branch-heads/7680@{#3951} Cr-Branched-From: 76b7d80e5cda23fe6537eed26d68c92e995c7f39-refs/heads/main@{#1582197} diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc -index e56cd25e65b0ba5db4ab39ba9ab0314ee13696d8..6918504a510d5a2a0aba3539156f72d53331d622 100644 +index 6918504a510d5a2a0aba3539156f72d53331d622..52aabbf3d5d52717e4c14e47c38cc3959194c973 100644 --- a/gpu/ipc/service/gpu_channel.cc +++ b/gpu/ipc/service/gpu_channel.cc -@@ -971,6 +971,11 @@ void GpuChannel::CreateCommandBuffer( +@@ -976,6 +976,11 @@ void GpuChannel::CreateCommandBuffer( return; } @@ -36,9 +36,9 @@ index e56cd25e65b0ba5db4ab39ba9ab0314ee13696d8..6918504a510d5a2a0aba3539156f72d5 int32_t stream_id = init_params->stream_id; CommandBufferId command_buffer_id = CommandBufferIdFromChannelAndRoute(client_id_, route_id); -@@ -1032,6 +1037,10 @@ void GpuChannel::DestroyCommandBuffer(int32_t route_id) { - TRACE_EVENT1("gpu", "GpuChannel::OnDestroyCommandBuffer", "route_id", - route_id); +@@ -1041,6 +1046,10 @@ void GpuChannel::DestroyCommandBuffer(int32_t route_id) { + return; + } + if (route_id <= static_cast(GpuChannelReservedRoutes::kMaxValue)) { + return; diff --git a/patches/chromium/cherry-pick-eeb3e031eb89.patch b/patches/chromium/cherry-pick-eeb3e031eb89.patch deleted file mode 100644 index b4a484b9b2..0000000000 --- a/patches/chromium/cherry-pick-eeb3e031eb89.patch +++ /dev/null @@ -1,373 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eugene Zemtsov -Date: Mon, 13 Apr 2026 22:52:33 -0700 -Subject: [M146] media: Zero-copy VP9 alpha decoding in VpxVideoDecoder - -Original change's description: -> media: Zero-copy VP9 alpha decoding in VpxVideoDecoder -> -> Configures the VP9 alpha decoder to use `memory_pool_` for external -> frame buffers, eliminating the need for `libyuv::CopyPlane`. -> -> The `VideoFrame` now wraps the alpha data directly from the pool using -> a second destruction observer. `AllocateAlphaPlaneForFrameBuffer` and -> `alpha_data` tracking are removed from `FrameBufferPool`. -> -> Bug: 500066234 -> Change-Id: I6e7cf13bcc8a5a1759acfd51961859c4c57fcbf2 -> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7737984 -> Reviewed-by: Ted (Chromium) Meyer -> Commit-Queue: Eugene Zemtsov -> Reviewed-by: Dale Curtis -> Cr-Commit-Position: refs/heads/main@{#1611919} - -(cherry picked from commit fc79e8cc2dfcc8f7ec8ee9cf0acf0993f32aec27) - -Bug: 501314839,500066234 -Change-Id: I6e7cf13bcc8a5a1759acfd51961859c4c57fcbf2 -Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7757063 -Reviewed-by: Dale Curtis -Commit-Queue: Eugene Zemtsov -Cr-Commit-Position: refs/branch-heads/7680@{#3937} -Cr-Branched-From: 76b7d80e5cda23fe6537eed26d68c92e995c7f39-refs/heads/main@{#1582197} - -diff --git a/media/base/frame_buffer_pool.cc b/media/base/frame_buffer_pool.cc -index e90f07036baab4056398c93a03f8751bbfaa5d69..e2aa3a9243e3ce45b5087853eb2bd7d7dae7acfe 100644 ---- a/media/base/frame_buffer_pool.cc -+++ b/media/base/frame_buffer_pool.cc -@@ -56,7 +56,6 @@ struct FrameBufferPool::FrameBuffer { - // Not using std::vector as resize() calls take a really long time - // for large buffers. - BytesArray data; -- BytesArray alpha_data; - bool held_by_library = false; - // Needs to be a counter since a frame buffer might be used multiple times. - int held_by_frame = 0; -@@ -148,31 +147,6 @@ void FrameBufferPool::ReleaseFrameBuffer(void* fb_priv) { - } - } - --base::span FrameBufferPool::AllocateAlphaPlaneForFrameBuffer( -- size_t min_size, -- void* fb_priv) { -- base::AutoLock lock(lock_); -- DCHECK(fb_priv); -- -- auto* frame_buffer = static_cast(fb_priv); -- DCHECK(IsUsedLocked(frame_buffer)); -- if (frame_buffer->alpha_data.size() < min_size) { -- // Free the existing |alpha_data| first so that the memory can be reused, -- // if possible. Note that the new array is purposely not initialized. -- frame_buffer->alpha_data = {}; -- uint8_t* data = nullptr; -- if (force_allocation_error_ || -- !base::UncheckedMalloc(min_size, reinterpret_cast(&data)) || -- !data) { -- return {}; -- } -- // SAFETY: We have just allocated `min_size` of memory for `data`. -- frame_buffer->alpha_data = -- UNSAFE_BUFFERS(BytesArray::FromOwningPointer(data, min_size)); -- } -- return frame_buffer->alpha_data; --} -- - base::OnceClosure FrameBufferPool::CreateFrameCallback(void* fb_priv) { - base::AutoLock lock(lock_); - -@@ -210,10 +184,9 @@ bool FrameBufferPool::OnMemoryDump( - size_t bytes_reserved = 0; - for (const auto& frame_buffer : frame_buffers_) { - if (IsUsedLocked(frame_buffer.get())) { -- bytes_used += frame_buffer->data.size() + frame_buffer->alpha_data.size(); -+ bytes_used += frame_buffer->data.size(); - } -- bytes_reserved += -- frame_buffer->data.size() + frame_buffer->alpha_data.size(); -+ bytes_reserved += frame_buffer->data.size(); - } - - memory_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, -diff --git a/media/base/frame_buffer_pool.h b/media/base/frame_buffer_pool.h -index ac839b8e8bfa00d2fea203be5248a56f04cecc71..2ccb01676b0e8e1e3ca1b3cb60f2883538f2f13c 100644 ---- a/media/base/frame_buffer_pool.h -+++ b/media/base/frame_buffer_pool.h -@@ -48,11 +48,6 @@ class MEDIA_EXPORT FrameBufferPool - // Called when a frame buffer allocation is no longer needed. - void ReleaseFrameBuffer(void* fb_priv); - -- // Allocates (or reuses) room for an alpha plane on a given frame buffer. -- // |fb_priv| must be a value previously returned by GetFrameBuffer(). -- base::span AllocateAlphaPlaneForFrameBuffer(size_t min_size, -- void* fb_priv); -- - // Generates a "no_longer_needed" closure that holds a reference to this pool; - // |fb_priv| must be a value previously returned by GetFrameBuffer(). The - // callback may be called on any thread. -diff --git a/media/base/frame_buffer_pool_unittest.cc b/media/base/frame_buffer_pool_unittest.cc -index a5b7bff2b8af3d2f9a531e894ec28e31e7823ac0..4cfdb1520cc18548fd91b2cca8b03a0124de944f 100644 ---- a/media/base/frame_buffer_pool_unittest.cc -+++ b/media/base/frame_buffer_pool_unittest.cc -@@ -32,12 +32,6 @@ TEST(FrameBufferPool, BasicFunctionality) { - EXPECT_NE(buf1.data(), buf2.data()); - std::ranges::fill(buf2, 0); - -- auto alpha = pool->AllocateAlphaPlaneForFrameBuffer(kBufferSize, priv1); -- ASSERT_FALSE(alpha.empty()); -- EXPECT_NE(alpha.data(), buf1.data()); -- EXPECT_NE(alpha.data(), buf2.data()); -- std::ranges::fill(alpha, 0); -- - EXPECT_EQ(2u, pool->get_pool_size_for_testing()); - - // Frames are not released immediately, so this should still show two frames. -@@ -52,7 +46,6 @@ TEST(FrameBufferPool, BasicFunctionality) { - EXPECT_EQ(1u, pool->get_pool_size_for_testing()); - - std::ranges::fill(buf1, 0); -- std::ranges::fill(alpha, 0); - - // This will release all memory since we're in the shutdown state. - std::move(frame_release_cb).Run(); -diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc -index 0be38f7ee110a0084854c571784e9dd3c8144f51..32cd3c423f4f01aa4cbe21ae71bf149f26a1deee 100644 ---- a/media/filters/vpx_video_decoder.cc -+++ b/media/filters/vpx_video_decoder.cc -@@ -269,7 +269,21 @@ bool VpxVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config) { - - DCHECK(!vpx_codec_alpha_); - vpx_codec_alpha_ = InitializeVpxContext(config); -- return !!vpx_codec_alpha_; -+ if (!vpx_codec_alpha_) { -+ return false; -+ } -+ -+ if (config.codec() == VideoCodec::kVP9) { -+ if (vpx_codec_set_frame_buffer_functions( -+ vpx_codec_alpha_.get(), &GetVP9FrameBuffer, &ReleaseVP9FrameBuffer, -+ memory_pool_.get())) { -+ DLOG(ERROR) << "Failed to configure external buffers for alpha. " -+ << vpx_codec_error(vpx_codec_alpha_.get()); -+ return false; -+ } -+ } -+ -+ return true; - } - - void VpxVideoDecoder::CloseDecoder() { -@@ -576,20 +590,13 @@ bool VpxVideoDecoder::CopyVpxImageToVideoFrame( - if (memory_pool_) { - DCHECK_EQ(VideoCodec::kVP9, config_.codec()); - if (vpx_image_alpha) { -+ CHECK_GT(vpx_image_alpha->stride[VPX_PLANE_Y], 0); - size_t alpha_plane_size = - vpx_image_alpha->stride[VPX_PLANE_Y] * vpx_image_alpha->d_h; -- auto alpha_plane = memory_pool_->AllocateAlphaPlaneForFrameBuffer( -- alpha_plane_size, vpx_image->fb_priv); -- if (alpha_plane.empty()) { -- error_status_ = DecoderStatus::Codes::kOutOfMemory; -- // In case of OOM, abort copy. -- return false; -- } -- libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], -- vpx_image_alpha->stride[VPX_PLANE_Y], -- alpha_plane.data(), -- vpx_image_alpha->stride[VPX_PLANE_Y], -- vpx_image_alpha->d_w, vpx_image_alpha->d_h); -+ // SAFETY: libvpx guarantees that the Y plane has at least `stride * d_h` -+ // bytes available. -+ auto alpha_plane = UNSAFE_BUFFERS(base::span( -+ vpx_image_alpha->planes[VPX_PLANE_Y], alpha_plane_size)); - *video_frame = VideoFrame::WrapExternalYuvaData( - codec_format, coded_size, gfx::Rect(visible_size), natural_size, - vpx_image->stride[VPX_PLANE_Y], vpx_image->stride[VPX_PLANE_U], -@@ -605,8 +612,14 @@ bool VpxVideoDecoder::CopyVpxImageToVideoFrame( - if (!(*video_frame)) - return false; - -- video_frame->get()->AddDestructionObserver( -- memory_pool_->CreateFrameCallback(vpx_image->fb_priv)); -+ (*video_frame) -+ ->AddDestructionObserver( -+ memory_pool_->CreateFrameCallback(vpx_image->fb_priv)); -+ if (vpx_image_alpha) { -+ (*video_frame) -+ ->AddDestructionObserver( -+ memory_pool_->CreateFrameCallback(vpx_image_alpha->fb_priv)); -+ } - return true; - } - -diff --git a/media/filters/vpx_video_decoder.h b/media/filters/vpx_video_decoder.h -index 7bcba319954ed43175e42c2dc1b991c5b6129138..2ab3767680ee408215bf2debb6f85c033f45af68 100644 ---- a/media/filters/vpx_video_decoder.h -+++ b/media/filters/vpx_video_decoder.h -@@ -104,8 +104,8 @@ class MEDIA_EXPORT VpxVideoDecoder : public OffloadableVideoDecoder { - std::unique_ptr vpx_codec_; - std::unique_ptr vpx_codec_alpha_; - -- // |memory_pool_| is a single-threaded memory pool used for VP9 decoding -- // with no alpha. |frame_pool_| is used for all other cases. -+ // |memory_pool_| is a thread-safe memory pool used for zero-copy VP9 decoding -+ // (both with and without alpha). |frame_pool_| is used for VP8. - scoped_refptr memory_pool_; - VideoFramePool frame_pool_; - -diff --git a/media/filters/vpx_video_decoder_unittest.cc b/media/filters/vpx_video_decoder_unittest.cc -index c7f6d13bd825425230b63d87c13466e49f3c3c59..5203645bc8ec89dd93827fc0cbebb92e803faac1 100644 ---- a/media/filters/vpx_video_decoder_unittest.cc -+++ b/media/filters/vpx_video_decoder_unittest.cc -@@ -176,6 +176,28 @@ class VpxVideoDecoderTest : public testing::Test { - output_frames_.push_back(std::move(frame)); - } - -+ // Extracts the compressed video data from the AVPacket and also checks for -+ // side data containing an alpha channel. If found, it copies the alpha data -+ // into the DecoderBuffer's side data. This is necessary because FFmpeg -+ // demuxes alpha channel data as side data associated with the video packet. -+ static scoped_refptr CreateBufferWithAlphaFromPacket( -+ const AVPacket* packet) { -+ auto buffer = DecoderBuffer::CopyFrom(AVPacketData(*packet)); -+ size_t side_data_size = 0; -+ uint8_t* side_data_ptr = av_packet_get_side_data( -+ packet, AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, &side_data_size); -+ if (side_data_size > 8) { -+ // SAFETY: The best we can do here is trust the size reported by ffmpeg. -+ auto side_data = -+ UNSAFE_BUFFERS(base::span(side_data_ptr, side_data_size)); -+ if (base::U64FromBigEndian(side_data.first<8u>()) == 1) { -+ buffer->WritableSideData().alpha_data = -+ base::HeapArray::CopiedFrom(side_data.subspan(8u)); -+ } -+ } -+ return buffer; -+ } -+ - MOCK_METHOD1(DecodeDone, void(DecoderStatus)); - - base::test::TaskEnvironment task_env_; -@@ -293,6 +315,68 @@ TEST_F(VpxVideoDecoderTest, SimpleFrameReuse) { - EXPECT_EQ(old_y_data, output_frames_.back()->data(VideoFrame::Plane::kY)); - } - -+TEST_F(VpxVideoDecoderTest, SimpleAlphaFrameReuse) { -+ VideoDecoderConfig config = TestVideoConfig::Normal(VideoCodec::kVP9); -+ config.Initialize( -+ config.codec(), config.profile(), -+ VideoDecoderConfig::AlphaMode::kHasAlpha, config.color_space_info(), -+ config.video_transformation(), config.coded_size(), config.visible_rect(), -+ config.natural_size(), config.extra_data(), config.encryption_scheme()); -+ InitializeWithConfig(config); -+ scoped_refptr alpha_frame = ReadTestDataFile("bear-vp9a.webm"); -+ -+ // Read frames from the webm file. -+ InMemoryUrlProtocol protocol(*alpha_frame, false); -+ FFmpegGlue glue(&protocol); -+ ASSERT_TRUE(glue.OpenContext()); -+ -+ auto packet = ScopedAVPacket::Allocate(); -+ -+ // Decode first frame -+ ASSERT_GE(av_read_frame(glue.format_context(), packet.get()), 0); -+ auto buffer = CreateBufferWithAlphaFromPacket(packet.get()); -+ Decode(buffer); -+ av_packet_unref(packet.get()); -+ -+ ASSERT_EQ(1u, output_frames_.size()); -+ scoped_refptr frame = std::move(output_frames_.front()); -+ EXPECT_EQ(PIXEL_FORMAT_I420A, frame->format()); -+ const uint8_t* old_y_data = frame->data(VideoFrame::Plane::kY); -+ const uint8_t* old_a_data = frame->data(VideoFrame::Plane::kA); -+ output_frames_.pop_back(); -+ -+ // Clear frame reference to return the frame to the pool. -+ frame = nullptr; -+ -+ // Decode second frame. -+ Decode(buffer); -+ const uint8_t* mid_y_data = -+ output_frames_.front()->data(VideoFrame::Plane::kY); -+ const uint8_t* mid_a_data = -+ output_frames_.front()->data(VideoFrame::Plane::kA); -+ output_frames_.clear(); -+ -+ // Issuing another decode should reuse buffers from the pool. -+ Decode(buffer); -+ -+ ASSERT_EQ(1u, output_frames_.size()); -+ const uint8_t* new_y_data = -+ output_frames_.back()->data(VideoFrame::Plane::kY); -+ const uint8_t* new_a_data = -+ output_frames_.back()->data(VideoFrame::Plane::kA); -+ -+ // The pool is shared, so buffers might be reused in a different order (e.g. Y -+ // might get the buffer previously used for A). Because libvpx allocates the -+ // new frame before releasing the old reference frame, we need to check across -+ // all previously allocated buffers. -+ bool reused_y = new_y_data == old_y_data || new_y_data == old_a_data || -+ new_y_data == mid_y_data || new_y_data == mid_a_data; -+ bool reused_a = new_a_data == old_y_data || new_a_data == old_a_data || -+ new_a_data == mid_y_data || new_a_data == mid_a_data; -+ EXPECT_TRUE(reused_y); -+ EXPECT_TRUE(reused_a); -+} -+ - TEST_F(VpxVideoDecoderTest, SimpleFormatChange) { - scoped_refptr large_frame = - ReadTestDataFile("vp9-I-frame-1280x720"); -@@ -312,9 +396,41 @@ TEST_F(VpxVideoDecoderTest, FrameValidAfterPoolDestruction) { - - // Write to the Y plane. The memory tools should detect a - // use-after-free if the storage was actually removed by pool destruction. -- memset(output_frames_.front()->writable_data(VideoFrame::Plane::kY), 0xff, -- output_frames_.front()->rows(VideoFrame::Plane::kY) * -- output_frames_.front()->stride(VideoFrame::Plane::kY)); -+ std::ranges::fill( -+ output_frames_.front()->writable_span(VideoFrame::Plane::kY), 0xff); -+} -+ -+TEST_F(VpxVideoDecoderTest, AlphaFrameValidAfterPoolDestruction) { -+ VideoDecoderConfig config = TestVideoConfig::Normal(VideoCodec::kVP9); -+ config.Initialize( -+ config.codec(), config.profile(), -+ VideoDecoderConfig::AlphaMode::kHasAlpha, config.color_space_info(), -+ config.video_transformation(), config.coded_size(), config.visible_rect(), -+ config.natural_size(), config.extra_data(), config.encryption_scheme()); -+ InitializeWithConfig(config); -+ scoped_refptr alpha_frame = ReadTestDataFile("bear-vp9a.webm"); -+ -+ InMemoryUrlProtocol protocol(*alpha_frame, false); -+ FFmpegGlue glue(&protocol); -+ ASSERT_TRUE(glue.OpenContext()); -+ -+ auto packet = ScopedAVPacket::Allocate(); -+ ASSERT_GE(av_read_frame(glue.format_context(), packet.get()), 0); -+ auto buffer = CreateBufferWithAlphaFromPacket(packet.get()); -+ Decode(std::move(buffer)); -+ av_packet_unref(packet.get()); -+ -+ ASSERT_EQ(1u, output_frames_.size()); -+ EXPECT_EQ(PIXEL_FORMAT_I420A, output_frames_.front()->format()); -+ -+ Destroy(); -+ -+ // Write to the Y and A planes. The memory tools should detect a -+ // use-after-free if the storage was actually removed by pool destruction. -+ std::ranges::fill( -+ output_frames_.front()->writable_span(VideoFrame::Plane::kY), 0xff); -+ std::ranges::fill( -+ output_frames_.front()->writable_span(VideoFrame::Plane::kA), 0xff); - } - - // The test stream uses profile 2, which needs high bit depth support in libvpx. -@@ -362,8 +478,7 @@ TEST_F(VpxVideoDecoderTest, MemoryPoolAllowsMultipleDisplay) { - Destroy(); - - // ASAN will be very unhappy with this line if the above is incorrect. -- memset(last_frame->writable_data(VideoFrame::Plane::kY), 0, -- last_frame->row_bytes(VideoFrame::Plane::kY)); -+ std::ranges::fill(last_frame->writable_span(VideoFrame::Plane::kY), 0); - } - #endif // !defined(LIBVPX_NO_HIGH_BIT_DEPTH) && !defined(ARCH_CPU_ARM_FAMILY) - diff --git a/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch b/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch index 918e375cf1..54dcc43833 100644 --- a/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch +++ b/patches/chromium/mas_avoid_private_macos_api_usage.patch.patch @@ -1209,7 +1209,7 @@ index a1068589ad844518038ee7bc15a3de9bc5cba525..1ff781c49f086ec8015c7d3c44567dbe } // namespace content diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn -index d368b2481156bb79c6e74c8b09a828eb2fa2d44c..07cbf495717714d71d977a8820e08050c3062526 100644 +index fa04ab07ac1a5a0b0ff2dec4dba6cb2d1a0ab2d0..f5d72a89c7229bf8e897c90660feca482ac82594 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn @@ -700,6 +700,7 @@ static_library("test_support") { @@ -1237,7 +1237,7 @@ index d368b2481156bb79c6e74c8b09a828eb2fa2d44c..07cbf495717714d71d977a8820e08050 ] if (!(is_chromeos && target_cpu == "arm64" && current_cpu == "arm")) { -@@ -3412,6 +3416,7 @@ test("content_unittests") { +@@ -3413,6 +3417,7 @@ test("content_unittests") { "//ui/shell_dialogs", "//ui/webui:test_support", "//url", diff --git a/patches/config.json b/patches/config.json index a0cd7b57a5..91f76139fd 100644 --- a/patches/config.json +++ b/patches/config.json @@ -15,6 +15,5 @@ { "patch_dir": "src/electron/patches/sqlite", "repo": "src/third_party/sqlite/src" }, { "patch_dir": "src/electron/patches/angle", "repo": "src/third_party/angle" }, { "patch_dir": "src/electron/patches/skia", "repo": "src/third_party/skia" }, - { "patch_dir": "src/electron/patches/pdfium", "repo": "src/third_party/pdfium" }, { "patch_dir": "src/electron/patches/libaom", "repo": "src/third_party/libaom/source/libaom" } ] diff --git a/patches/libaom/.patches b/patches/libaom/.patches index 05c4be2b46..26ffdd0722 100644 --- a/patches/libaom/.patches +++ b/patches/libaom/.patches @@ -1,4 +1,2 @@ -cherry-pick-4369bd1258dc.patch -cherry-pick-a047955845e5.patch cherry-pick-c61e9586156f.patch cherry-pick-395efd18d8ef.patch diff --git a/patches/libaom/cherry-pick-4369bd1258dc.patch b/patches/libaom/cherry-pick-4369bd1258dc.patch deleted file mode 100644 index 99007b65af..0000000000 --- a/patches/libaom/cherry-pick-4369bd1258dc.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: James Zern -Date: Fri, 27 Mar 2026 10:56:13 -0700 -Subject: av1_nonrd_pick_inter_mode_sb: add missing ref_frame_flags check - -Before calling `set_block_source_sad()` ensure `LAST_FRAME` is -available. Fixes a crash that may present as a use after free (UAF). - -Bug: 495477995, 495996858 -Change-Id: I61452ce412fb9071c3370b4350ed8878013a8355 -(cherry picked from commit 4369bd1258dc99fa759916d9aba6509cdda9d877) - -diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c -index f2010062323b0ff4a1236ef63516d9b2d8f3007a..0f2a1c780a56a51f69bba8893fea9d9ad98b85a3 100644 ---- a/av1/encoder/nonrd_pickmode.c -+++ b/av1/encoder/nonrd_pickmode.c -@@ -3440,6 +3440,7 @@ void av1_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, - !x->force_zeromv_skip_for_blk && - x->content_state_sb.source_sad_nonrd != kZeroSad && - x->source_variance == 0 && bsize < cm->seq_params->sb_size && -+ (cpi->ref_frame_flags & AOM_LAST_FLAG) && - search_state.yv12_mb[LAST_FRAME][0].width == cm->width && - search_state.yv12_mb[LAST_FRAME][0].height == cm->height) { - set_block_source_sad(cpi, x, bsize, &search_state.yv12_mb[LAST_FRAME][0]); diff --git a/patches/libaom/cherry-pick-a047955845e5.patch b/patches/libaom/cherry-pick-a047955845e5.patch deleted file mode 100644 index af2b7204f2..0000000000 --- a/patches/libaom/cherry-pick-a047955845e5.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Marco Paniconi -Date: Sun, 29 Mar 2026 20:27:20 -0700 -Subject: Set force_mv_inter_layer earlier in skip_inter_mode - -For nonrd_pickmode: move the setting of -force_mv_inter_layer earlier in the -skip_inter_mode_nonrd(), to make sure it always -get set (in case of false return in that function). - -Thie prevents the usage of a scaled_ref in pickmode -(combined_motion search) when it has actually not been -set/scaled in av1_scale_references (before encoding). - -Fixes a crash for use after free (UAF), reported -in the issues below. - -Added svc unittest to generate the issue. Also added -assert check for scaled_ref in combined_motion_search. - -Bug: 495477995, 495996858 -Change-Id: I578d19156d97a50546edc9422bc3581566f1236e -(cherry picked from commit a047955845e50e43786d51cdefcfc9e87804ed61) - -diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c -index 0f2a1c780a56a51f69bba8893fea9d9ad98b85a3..942b8ab23a2d448877c8801940fee4d0baae9aef 100644 ---- a/av1/encoder/nonrd_pickmode.c -+++ b/av1/encoder/nonrd_pickmode.c -@@ -192,7 +192,7 @@ static int combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x, - int *rate_mv, int64_t best_rd_sofar, - int use_base_mv) { - MACROBLOCKD *xd = &x->e_mbd; -- const AV1_COMMON *cm = &cpi->common; -+ AV1_COMMON *cm = &cpi->common; - const SPEED_FEATURES *sf = &cpi->sf; - MB_MODE_INFO *mi = xd->mi[0]; - int step_param = (sf->rt_sf.fullpel_search_step_param) -@@ -207,6 +207,14 @@ static int combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x, - int cost_list[5]; - int search_subpel = 1; - -+ if (av1_is_scaled(get_ref_scale_factors(cm, ref))) { -+ const YV12_BUFFER_CONFIG *scaled_ref = av1_get_scaled_ref_frame(cpi, ref); -+ (void)scaled_ref; -+ assert(scaled_ref != NULL); -+ assert(scaled_ref->y_crop_width == cm->width && -+ scaled_ref->y_crop_height == cm->height); -+ } -+ - start_mv = get_fullmv_from_mv(&ref_mv); - - if (!use_base_mv) -@@ -2490,6 +2498,23 @@ static AOM_FORCE_INLINE bool skip_inter_mode_nonrd( - (*this_mode != GLOBALMV || *ref_frame != LAST_FRAME)) - return true; - -+ *force_mv_inter_layer = 0; -+ if (cpi->ppi->use_svc && svc->spatial_layer_id > 0 && -+ ((*ref_frame == LAST_FRAME && svc->skip_mvsearch_last) || -+ (*ref_frame == GOLDEN_FRAME && svc->skip_mvsearch_gf) || -+ (*ref_frame == ALTREF_FRAME && svc->skip_mvsearch_altref))) { -+ // Only test mode if NEARESTMV/NEARMV is (svc_mv.mv.col, svc_mv.mv.row), -+ // otherwise set NEWMV to (svc_mv.mv.col, svc_mv.mv.row). -+ // Skip newmv and filter search. -+ *force_mv_inter_layer = 1; -+ if (*this_mode == NEWMV) { -+ search_state->frame_mv[*this_mode][*ref_frame] = svc_mv; -+ } else if (search_state->frame_mv[*this_mode][*ref_frame].as_int != -+ svc_mv.as_int) { -+ return true; -+ } -+ } -+ - // If the segment reference frame feature is enabled then do nothing if the - // current ref frame is not allowed. - if (segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) { -@@ -2565,23 +2590,6 @@ static AOM_FORCE_INLINE bool skip_inter_mode_nonrd( - return true; - } - -- *force_mv_inter_layer = 0; -- if (cpi->ppi->use_svc && svc->spatial_layer_id > 0 && -- ((*ref_frame == LAST_FRAME && svc->skip_mvsearch_last) || -- (*ref_frame == GOLDEN_FRAME && svc->skip_mvsearch_gf) || -- (*ref_frame == ALTREF_FRAME && svc->skip_mvsearch_altref))) { -- // Only test mode if NEARESTMV/NEARMV is (svc_mv.mv.col, svc_mv.mv.row), -- // otherwise set NEWMV to (svc_mv.mv.col, svc_mv.mv.row). -- // Skip newmv and filter search. -- *force_mv_inter_layer = 1; -- if (*this_mode == NEWMV) { -- search_state->frame_mv[*this_mode][*ref_frame] = svc_mv; -- } else if (search_state->frame_mv[*this_mode][*ref_frame].as_int != -- svc_mv.as_int) { -- return true; -- } -- } -- - // For screen content: skip mode testing based on source_sad. - if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN && - !x->force_zeromv_skip_for_blk) { -diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc -index 0df678212acb0519aa4420ae57186840e12c682c..2f68ba7a214932b284a6eacbe1a9b5b474b6c659 100644 ---- a/test/svc_datarate_test.cc -+++ b/test/svc_datarate_test.cc -@@ -247,6 +247,7 @@ class DatarateTestSVC - external_resize_pattern_ = 0; - dynamic_tl_ = false; - dynamic_scale_factors_ = false; -+ disable_last_ref_ = false; - } - - void PreEncodeFrameHook(::libaom_test::VideoSource *video, -@@ -302,7 +303,7 @@ class DatarateTestSVC - spatial_layer_id, multi_ref_, comp_pred_, - (video->frame() % cfg_.kf_max_dist) == 0, dynamic_enable_disable_mode_, - rps_mode_, rps_recovery_frame_, simulcast_mode_, use_last_as_scaled_, -- use_last_as_scaled_single_ref_); -+ use_last_as_scaled_single_ref_, disable_last_ref_); - if (intra_only_ == 1 && frame_sync_ > 0) { - // Set an Intra-only frame on SL0 at frame_sync_. - // In order to allow decoding to start on SL0 in mid-sequence we need to -@@ -964,7 +965,7 @@ class DatarateTestSVC - int multi_ref, int comp_pred, int is_key_frame, - int dynamic_enable_disable_mode, int rps_mode, int rps_recovery_frame, - int simulcast_mode, bool use_last_as_scaled, -- bool use_last_as_scaled_single_ref) { -+ bool use_last_as_scaled_single_ref, bool disable_last_ref) { - int lag_index = 0; - int base_count = frame_cnt >> 2; - layer_id->spatial_layer_id = spatial_layer; -@@ -1164,6 +1165,11 @@ class DatarateTestSVC - if (dynamic_enable_disable_mode == 1 && - layer_id->spatial_layer_id == number_spatial_layers_ - 1) - ref_frame_config->reference[0] = 0; -+ // Always disable LAST reference under this flag. use GOLDEN reference. -+ if (disable_last_ref) { -+ ref_frame_config->reference[0] = 0; -+ ref_frame_config->reference[3] = 1; -+ } - return layer_flags; - } - -@@ -1508,6 +1514,23 @@ class DatarateTestSVC - CheckDatarate(0.80, 1.60); - } - -+ virtual void BasicRateTargetingSVC1TL2SLDisableLASTTest() { -+ SetUpCbr(); -+ cfg_.g_error_resilient = 0; -+ -+ ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, -+ 288, 30, 1, 0, 300); -+ const int bitrate_array[2] = { 300, 600 }; -+ cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)]; -+ ResetModel(); -+ disable_last_ref_ = true; -+ screen_mode_ = true; -+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); -+#if CONFIG_AV1_DECODER -+ EXPECT_EQ((int)GetMismatchFrames(), 0); -+#endif -+ } -+ - virtual void BasicRateTargetingSVC3TL3SLIntraStartDecodeBaseMidSeq() { - SetUpCbr(); - cfg_.rc_max_quantizer = 56; -@@ -2380,6 +2403,7 @@ class DatarateTestSVC - int external_resize_pattern_; - bool dynamic_tl_; - bool dynamic_scale_factors_; -+ bool disable_last_ref_; - }; - - // Check basic rate targeting for CBR, for 3 temporal layers, 1 spatial. -@@ -2458,6 +2482,12 @@ TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL2SL) { - BasicRateTargetingSVC1TL2SLTest(); - } - -+// Check basic rate targeting for CBR, for 2 spatial layers, 1 temporal. -+// Disable the usage of LAST referenc frame. -+TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL2SLDisableLAST) { -+ BasicRateTargetingSVC1TL2SLDisableLASTTest(); -+} -+ - // Check basic rate targeting for CBR, for 3 spatial layers, 3 temporal, - // with Intra-only frame inserted in the stream. Verify that we can start - // decoding the SL0 stream at the intra_only frame in mid-sequence. diff --git a/patches/pdfium/.patches b/patches/pdfium/.patches deleted file mode 100644 index 615a9572d0..0000000000 --- a/patches/pdfium/.patches +++ /dev/null @@ -1,2 +0,0 @@ -cherry-pick-ca8a943c247c.patch -cherry-pick-bce2e6728279.patch diff --git a/patches/pdfium/cherry-pick-bce2e6728279.patch b/patches/pdfium/cherry-pick-bce2e6728279.patch deleted file mode 100644 index e4a6ba33b7..0000000000 --- a/patches/pdfium/cherry-pick-bce2e6728279.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Tom Sepez -Date: Tue, 7 Apr 2026 15:50:30 -0700 -Subject: Use safe arithmetic in CFX_PSRenderer::DrawDIBits() - -Hardening suggestion from the AI bot. - -Bug: 500036290 -Change-Id: Ie521629d06ba944f610b941a8c9e9505fa29aea7 -Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/145731 -Reviewed-by: Lei Zhang -Commit-Queue: Tom Sepez - -diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp -index b38f1a2b7c3271769e609763be2e183f2890ebb3..b8710e50ed01233b2aefbf1760e26e05964b315e 100644 ---- a/core/fxge/win32/cfx_psrenderer.cpp -+++ b/core/fxge/win32/cfx_psrenderer.cpp -@@ -620,8 +620,16 @@ bool CFX_PSRenderer::DrawDIBits(RetainPtr bitmap, - encoder_iface_->pJpegEncodeFunc(bitmap, &output_buf, &output_size)) { - filter = "/DCTDecode filter "; - } else { -- int src_pitch = width * bytes_per_pixel; -- output_size = height * src_pitch; -+ FX_SAFE_UINT32 safe_pitch = bytes_per_pixel; -+ safe_pitch *= width; -+ FX_SAFE_UINT32 safe_output_size = safe_pitch; -+ safe_output_size *= height; -+ if (!safe_output_size.IsValid()) { -+ WriteString("\nQ\n"); -+ return false; -+ } -+ uint32_t src_pitch = safe_pitch.ValueOrDie(); -+ output_size = safe_output_size.ValueOrDie(); - output_buf = FX_Alloc(uint8_t, output_size); - for (int row = 0; row < height; row++) { - const uint8_t* src_scan = bitmap->GetScanline(row).data(); diff --git a/patches/pdfium/cherry-pick-ca8a943c247c.patch b/patches/pdfium/cherry-pick-ca8a943c247c.patch deleted file mode 100644 index 52a0abbb78..0000000000 --- a/patches/pdfium/cherry-pick-ca8a943c247c.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lei Zhang -Date: Fri, 27 Mar 2026 14:52:16 -0700 -Subject: Patch an overflow in libtiff - -Apply fix [1] from upstream, which is not in the most recent versioned -release. - -[1] https://gitlab.com/libtiff/libtiff/-/commit/0f726d9 - -Bug: 496907110 -Change-Id: Ic8665879ebdd4445f473e9a1e156cfc42c294d51 -Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/145550 -Reviewed-by: Andy Phan -Commit-Queue: Lei Zhang - -diff --git a/third_party/libtiff/0034-tiff-jpeg-overflow.patch b/third_party/libtiff/0034-tiff-jpeg-overflow.patch -new file mode 100644 -index 0000000000000000000000000000000000000000..ba6086a38adfa0bd7726affda0f11381e04501e5 ---- /dev/null -+++ b/third_party/libtiff/0034-tiff-jpeg-overflow.patch -@@ -0,0 +1,25 @@ -+commit 0f726d9477a11e15eb67ca349c03907f6cfb82a9 -+Author: Mikhail Khachaiants -+Date: Mon Dec 1 22:26:34 2025 +0200 -+ -+ tif_jpeg: reject mismatched JPEG data precision to avoid write overflow -+ -+ Ensure TIFF BitsPerSample matches both BITS_IN_JSAMPLE and the JPEG -+ header data_precision for JPEG-compressed images. This prevents -+ under-sized scanline buffers that can lead to write buffer overflows -+ in jdcolor.c/null_convert when decoding malformed inputs. -+ -+diff --git a/libtiff/tif_jpeg.c b/libtiff/tif_jpeg.c -+index aba5f99b..4d6370b5 100644 -+--- a/libtiff/tif_jpeg.c -++++ b/libtiff/tif_jpeg.c -+@@ -1282,7 +1282,8 @@ int TIFFJPEGIsFullStripRequired(TIFF *tif) -+ sp->cinfo.d.data_precision = td->td_bitspersample; -+ sp->cinfo.d.bits_in_jsample = td->td_bitspersample; -+ #else -+- if (sp->cinfo.d.data_precision != td->td_bitspersample) -++ if (td->td_bitspersample != BITS_IN_JSAMPLE || -++ sp->cinfo.d.data_precision != td->td_bitspersample) -+ { -+ TIFFErrorExtR(tif, module, "Improper JPEG data precision"); -+ return (0); -diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium -index 9953e767853bcd30683cc24d0d1839c916659185..e3f352d747007641b5d0bd2256a5dbc8af7c20af 100644 ---- a/third_party/libtiff/README.pdfium -+++ b/third_party/libtiff/README.pdfium -@@ -19,3 +19,4 @@ Local Modifications: - 0028-nstrips-OOM.patch: return error for excess number of tiles/strips. - 0031-safe_size_ingtStripContig.patch: return error if the size to read overflow from int32. - 0033-avail-out-overflow.patch: signed comparison in PixarLogDecode(). -+0034-tiff-jpeg-overflow.patch: reject mismatched JPEG data precision. -diff --git a/third_party/libtiff/tif_jpeg.c b/third_party/libtiff/tif_jpeg.c -index 5281457d936a0dfa5f877c6a7efff6a65066f520..a9764f073db04d6e593e421105d0f59efbfbbeb2 100644 ---- a/third_party/libtiff/tif_jpeg.c -+++ b/third_party/libtiff/tif_jpeg.c -@@ -1287,7 +1287,8 @@ int TIFFJPEGIsFullStripRequired(TIFF *tif) - sp->cinfo.d.data_precision = td->td_bitspersample; - sp->cinfo.d.bits_in_jsample = td->td_bitspersample; - #else -- if (sp->cinfo.d.data_precision != td->td_bitspersample) -+ if (td->td_bitspersample != BITS_IN_JSAMPLE || -+ sp->cinfo.d.data_precision != td->td_bitspersample) - { - TIFFErrorExtR(tif, module, "Improper JPEG data precision"); - return (0); diff --git a/patches/skia/.patches b/patches/skia/.patches index 010b849ea8..d40e174d01 100644 --- a/patches/skia/.patches +++ b/patches/skia/.patches @@ -1,3 +1,2 @@ -cherry-pick-0566b2f5f0d1.patch cherry-pick-3f9969421ad5.patch cherry-pick-8c705ac86366.patch diff --git a/patches/skia/cherry-pick-0566b2f5f0d1.patch b/patches/skia/cherry-pick-0566b2f5f0d1.patch deleted file mode 100644 index 75716a1e65..0000000000 --- a/patches/skia/cherry-pick-0566b2f5f0d1.patch +++ /dev/null @@ -1,651 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Ludwig -Date: Wed, 1 Apr 2026 09:48:48 -0400 -Subject: Use 16-bit size for ResourceKeys - -Internally, ResourceKey required the size to fit into a uint16_t so this -makes that explicit in the public API. It also changes how the size is -stored to instead record the num32DataCount directly and then convert to -bytes as needed, whereas previously it was requiring that the actual -byte count fit into a uint16_t. This gives a bit more head room. - -Call sites to the ResourceKey builders are updated to now have the -responsibility of checking that their size can fit into a uint16_t. For -the most part, these were fixed or trivially small variable key sizes. -The two exceptions were Ganesh's style key (with dashes) and its -inherited key system for shapes with applied styles and path effects. -They now have reasonable limits to prevent the keys from growing bigger -than about 1kb. - -Bug: b/495700484 -Change-Id: I6ac4f17628b9a2e1a777c473b74e6d1f5c68b27d -Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1199497 -Reviewed-by: Robert Phillips -Commit-Queue: Michael Ludwig - -diff --git a/src/gpu/ResourceKey.h b/src/gpu/ResourceKey.h -index f8dee7983036a95d2f5fd7404553916b5c616e83..19851a67653669058361570c615d9be45dc5153a 100644 ---- a/src/gpu/ResourceKey.h -+++ b/src/gpu/ResourceKey.h -@@ -19,6 +19,7 @@ - - #include - #include -+#include - #include - #include - -@@ -77,14 +78,10 @@ public: - } - - protected: -- Builder(ResourceKey* key, uint32_t domain, int data32Count) : fKey(key) { -- size_t count = SkToSizeT(data32Count); -+ Builder(ResourceKey* key, uint16_t domain, uint16_t data32Count) : fKey(key) { - SkASSERT(domain != kInvalidDomain); -- key->fKey.reset(kMetaDataCnt + count); -- size_t size = (count + kMetaDataCnt) * sizeof(uint32_t); -- SkASSERT(SkToU16(size) == size); -- SkASSERT(SkToU16(domain) == domain); -- key->fKey[kDomainAndSize_MetaDataIdx] = SkToU32(domain | (size << 16)); -+ key->fKey.reset(kMetaDataCnt + data32Count); -+ key->fKey[kDomainAndSize_MetaDataIdx] = domain | (data32Count << 16); - } - - private: -@@ -92,7 +89,7 @@ public: - }; - - protected: -- static const uint32_t kInvalidDomain = 0; -+ static const uint16_t kInvalidDomain = 0; - - ResourceKey() { this->reset(); } - -@@ -118,10 +115,10 @@ protected: - return *this; - } - -- uint32_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; } -+ uint16_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; } - - /** size of the key data, excluding meta-data (hash, domain, etc). */ -- size_t dataSize() const { return this->size() - 4 * kMetaDataCnt; } -+ size_t dataSize() const { return (fKey[kDomainAndSize_MetaDataIdx] >> 16) * sizeof(uint32_t); } - - /** ptr to the key data, excluding meta-data (hash, domain, etc). */ - const uint32_t* data() const { -@@ -149,14 +146,17 @@ protected: - private: - enum MetaDataIdx { - kHash_MetaDataIdx, -- // The key domain and size are packed into a single uint32_t. -+ // The key domain and size are packed into a single uint32_t. The stored size is in units -+ // of uint32_t and does not include the metadata, i.e. it stores the data32Count provided -+ // to the original key builder. - kDomainAndSize_MetaDataIdx, - - kLastMetaDataIdx = kDomainAndSize_MetaDataIdx - }; - static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1; - -- size_t internalSize() const { return fKey[kDomainAndSize_MetaDataIdx] >> 16; } -+ // Total size in bytes, including metadata -+ size_t internalSize() const { return this->dataSize() + sizeof(uint32_t) * kMetaDataCnt; } - - void validate() const { - SkASSERT(this->isValid()); -@@ -197,7 +197,7 @@ private: - class ScratchKey : public ResourceKey { - public: - /** Uniquely identifies the type of resource that is cached as scratch. */ -- typedef uint32_t ResourceType; -+ typedef uint16_t ResourceType; - - /** Generate a unique ResourceType. */ - static ResourceType GenerateResourceType(); -@@ -219,7 +219,7 @@ public: - - class Builder : public ResourceKey::Builder { - public: -- Builder(ScratchKey* key, ResourceType type, int data32Count) -+ Builder(ScratchKey* key, ResourceType type, uint16_t data32Count) - : ResourceKey::Builder(key, type, data32Count) {} - }; - }; -@@ -240,7 +240,7 @@ public: - */ - class UniqueKey : public ResourceKey { - public: -- typedef uint32_t Domain; -+ typedef uint16_t Domain; - /** Generate a Domain for unique keys. */ - static Domain GenerateDomain(); - -@@ -279,17 +279,17 @@ public: - - class Builder : public ResourceKey::Builder { - public: -- Builder(UniqueKey* key, Domain type, int data32Count, const char* tag = nullptr) -+ Builder(UniqueKey* key, Domain type, uint16_t data32Count, const char* tag = nullptr) - : ResourceKey::Builder(key, type, data32Count) { - key->fTag = tag; - } - - /** Used to build a key that wraps another key and adds additional data. */ -- Builder(UniqueKey* key, const UniqueKey& innerKey, Domain domain, int extraData32Cnt, -+ Builder(UniqueKey* key, const UniqueKey& innerKey, Domain domain, uint16_t extraData32Cnt, - const char* tag = nullptr) - : ResourceKey::Builder(key, - domain, -- Data32CntForInnerKey(innerKey) + extraData32Cnt) { -+ Data32CntForInnerKey(innerKey, extraData32Cnt)) { - SkASSERT(&innerKey != key); - // add the inner key to the end of the key so that op[] can be indexed normally. - uint32_t* innerKeyData = &this->operator[](extraData32Cnt); -@@ -300,9 +300,15 @@ public: - } - - private: -- static int Data32CntForInnerKey(const UniqueKey& innerKey) { -- // key data + domain -- return SkToInt((innerKey.dataSize() >> 2) + 1); -+ static uint16_t Data32CntForInnerKey(const UniqueKey& innerKey, uint16_t extraData32Cnt) { -+ // key data + domain + extraData32Cnt needs to fit into a uint16_t. This key builder is -+ // only used in Ganesh for wrapping textures -+ uint16_t innerData32Cnt = innerKey.dataSize() >> 2; -+ // The Builder API doesn't have a way to return a failure, so if this is somehow -+ // exceeded, then we have no way to recover. -+ SkASSERT_RELEASE((uint32_t) extraData32Cnt + (uint32_t) innerData32Cnt + 1 <= -+ (uint32_t) std::numeric_limits::max()); -+ return innerData32Cnt + extraData32Cnt + 1; - } - }; - -diff --git a/src/gpu/ganesh/GrStyle.cpp b/src/gpu/ganesh/GrStyle.cpp -index 5d7bc9c1d971bbcf3df0fa720f660f23dfdcbab5..d1bdcf5a117b61f3a8ac3010d6d3cc3702f82ced 100644 ---- a/src/gpu/ganesh/GrStyle.cpp -+++ b/src/gpu/ganesh/GrStyle.cpp -@@ -18,8 +18,18 @@ - - int GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) { - static_assert(sizeof(uint32_t) == sizeof(SkScalar)); -+ -+ // We embed the dash interval pattern into the key, and the key size must fit within 16-bits. -+ // However, we put a more conservative upper limit on the dashes because we don't want to keep -+ // key memory locked up in caches during pathological cases. -+ static constexpr int kDashIntervalKeyLimit = 512; -+ - int size = 0; - if (style.isDashed()) { -+ if (style.dashIntervalCnt() > kDashIntervalKeyLimit) { -+ return -1; // Disable caching for pathologically large dash patterns -+ } -+ - // One scalar for scale, one for dash phase, and one for each dash value. - size += 2 + style.dashIntervalCnt(); - } else if (style.pathEffect()) { -diff --git a/src/gpu/ganesh/GrStyle.h b/src/gpu/ganesh/GrStyle.h -index 41b0ce9db13e57db63cd1949dc87b9c20023fcc6..252b975e1e66dd654326449f3c9cbc317b8a2fda 100644 ---- a/src/gpu/ganesh/GrStyle.h -+++ b/src/gpu/ganesh/GrStyle.h -@@ -74,6 +74,8 @@ public: - * into a key. This occurs when there is a path effect that is not a dash. The key can - * either reflect just the path effect (if one) or the path effect and the strokerec. Note - * that a simple fill has a zero sized key. -+ * -+ * If a positive value is returned, it will fit in a uint16_t. - */ - static int KeySize(const GrStyle&, Apply, uint32_t flags = 0); - -diff --git a/src/gpu/ganesh/geometry/GrStyledShape.cpp b/src/gpu/ganesh/geometry/GrStyledShape.cpp -index 3c2b942aa6c614a6312e6695309cb9fc8dd6f5d5..6aa4daa3f8d76ab0dfe062dfb2f4b1503a8a5e1f 100644 ---- a/src/gpu/ganesh/geometry/GrStyledShape.cpp -+++ b/src/gpu/ganesh/geometry/GrStyledShape.cpp -@@ -19,6 +19,7 @@ - - #include - #include -+#include - #include - - -@@ -141,12 +142,12 @@ static void write_path_key_from_data(const SkPath& path, uint32_t* origKey) { - SkASSERT(key - origKey == path_key_from_data_size(path)); - } - --int GrStyledShape::unstyledKeySize() const { -+uint16_t GrStyledShape::unstyledKeySize() const { - if (fInheritedKey.count()) { -- return fInheritedKey.count(); -+ return SkTo(fInheritedKey.count()); - } - -- int count = 1; // Every key has the state flags from the GrShape -+ uint16_t count = 1; // Every key has the state flags from the GrShape - switch(fShape.type()) { - case GrShape::Type::kPoint: - static_assert(0 == sizeof(SkPoint) % sizeof(uint32_t)); -@@ -170,11 +171,13 @@ int GrStyledShape::unstyledKeySize() const { - break; - case GrShape::Type::kPath: { - if (0 == fGenID) { -- return -1; // volatile, so won't be keyed -+ return 0; // volatile, so won't be keyed - } -+ // When >= 0, `dataKeySize` is a reasonably small number bounded by -+ // kMaxKeyFromDataVerbCnt since point count is derived from verb count. - int dataKeySize = path_key_from_data_size(fShape.path()); - if (dataKeySize >= 0) { -- count += dataKeySize; -+ count += SkTo(dataKeySize); - } else { - count++; // Just adds the gen ID. - } -@@ -251,6 +254,7 @@ void GrStyledShape::writeUnstyledKey(uint32_t* key) const { - - void GrStyledShape::setInheritedKey(const GrStyledShape &parent, GrStyle::Apply apply, - SkScalar scale) { -+ static constexpr int kInheritedKeyLimit = 1024; - SkASSERT(!fInheritedKey.count()); - // If the output shape turns out to be simple, then we will just use its geometric key - if (fShape.isPath()) { -@@ -264,7 +268,7 @@ void GrStyledShape::setInheritedKey(const GrStyledShape &parent, GrStyle::Apply - bool useParentGeoKey = !parentCnt; - if (useParentGeoKey) { - parentCnt = parent.unstyledKeySize(); -- if (parentCnt < 0) { -+ if (!parentCnt) { - // The parent's geometry has no key so we will have no key. - fGenID = 0; - return; -@@ -283,7 +287,12 @@ void GrStyledShape::setInheritedKey(const GrStyledShape &parent, GrStyle::Apply - // we try to get a key for the shape. - fGenID = 0; - return; -+ } else if (parentCnt + styleCnt > kInheritedKeyLimit) { -+ // Prevent chained path effects and styles from growing the key too large -+ fGenID = 0; -+ return; - } -+ - fInheritedKey.reset(parentCnt + styleCnt); - if (useParentGeoKey) { - // This will be the geo key. -diff --git a/src/gpu/ganesh/geometry/GrStyledShape.h b/src/gpu/ganesh/geometry/GrStyledShape.h -index 97db583a5cf8aa8c7fe8c0e054ef622ca6945744..ed4345355478121dfedb1a894e159b80c4fca304 100644 ---- a/src/gpu/ganesh/geometry/GrStyledShape.h -+++ b/src/gpu/ganesh/geometry/GrStyledShape.h -@@ -252,11 +252,11 @@ public: - - /** - * Gets the size of the key for the shape represented by this GrStyledShape (ignoring its -- * styling). A negative value is returned if the shape has no key (shouldn't be cached). -+ * styling). A zero value is returned if the shape has no key (shouldn't be cached). - */ -- int unstyledKeySize() const; -+ uint16_t unstyledKeySize() const; - -- bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; } -+ bool hasUnstyledKey() const { return this->unstyledKeySize() > 0; } - - /** - * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough -diff --git a/src/gpu/ganesh/image/GrImageUtils.cpp b/src/gpu/ganesh/image/GrImageUtils.cpp -index a88ff15c0a59f1a5f417aa37f243385503a3dfd9..8fd9ea6a55e4a77c793c7af2361aab7e06c63f08 100644 ---- a/src/gpu/ganesh/image/GrImageUtils.cpp -+++ b/src/gpu/ganesh/image/GrImageUtils.cpp -@@ -683,8 +683,7 @@ GrSurfaceProxyView FindOrMakeCachedMipmappedView(GrRecordingContext* rContext, - SkASSERT(baseKey.isValid()); - skgpu::UniqueKey mipmappedKey; - static const skgpu::UniqueKey::Domain kMipmappedDomain = skgpu::UniqueKey::GenerateDomain(); -- { // No extra values beyond the domain are required. Must name the var to please -- // clang-tidy. -+ { // No extra values beyond the domain are required. Must name the var to please clang-tidy. - skgpu::UniqueKey::Builder b(&mipmappedKey, baseKey, kMipmappedDomain, 0); - } - SkASSERT(mipmappedKey.isValid()); -diff --git a/src/gpu/ganesh/ops/TriangulatingPathRenderer.cpp b/src/gpu/ganesh/ops/TriangulatingPathRenderer.cpp -index 124e51842eafbf7d3b010ca3232731d549515a9b..1bf3038847223c8167fa60c852c23216d186c5cc 100644 ---- a/src/gpu/ganesh/ops/TriangulatingPathRenderer.cpp -+++ b/src/gpu/ganesh/ops/TriangulatingPathRenderer.cpp -@@ -282,8 +282,7 @@ private: - bool inverseFill = shape.inverseFilled(); - - static constexpr int kClipBoundsCnt = sizeof(devClipBounds) / sizeof(uint32_t); -- int shapeKeyDataCnt = shape.unstyledKeySize(); -- SkASSERT(shapeKeyDataCnt >= 0); -+ uint16_t shapeKeyDataCnt = shape.unstyledKeySize(); - skgpu::UniqueKey::Builder builder(key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path"); - shape.writeUnstyledKey(&builder[0]); - // For inverse fills, the tessellation is dependent on clip bounds. -diff --git a/src/gpu/graphite/GraphiteResourceKey.h b/src/gpu/graphite/GraphiteResourceKey.h -index 12e72d1b24f45ac5885a125cb3d52cb648a55402..d52f0099a722aaf2a4b655abf6bf8c0ea26dcf57 100644 ---- a/src/gpu/graphite/GraphiteResourceKey.h -+++ b/src/gpu/graphite/GraphiteResourceKey.h -@@ -46,7 +46,7 @@ public: - - class Builder : public ResourceKey::Builder { - public: -- Builder(GraphiteResourceKey* key, ResourceType type, int data32Count) -+ Builder(GraphiteResourceKey* key, ResourceType type, uint16_t data32Count) - : ResourceKey::Builder(key, type, data32Count) {} - }; - }; -diff --git a/src/gpu/graphite/RasterPathUtils.cpp b/src/gpu/graphite/RasterPathUtils.cpp -index 1d8b5563e41bf8e3f515438c666760b228c3947c..8557d35bc4803cf71224457d103c3a9ce874012c 100644 ---- a/src/gpu/graphite/RasterPathUtils.cpp -+++ b/src/gpu/graphite/RasterPathUtils.cpp -@@ -140,7 +140,7 @@ skgpu::UniqueKey GeneratePathMaskKey(const Shape& shape, - skgpu::UniqueKey maskKey; - { - static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain(); -- int styleKeySize = 7; -+ uint16_t styleKeySize = 7; - if (!strokeRec.isHairlineStyle() && !strokeRec.isFillStyle()) { - // Add space for width and miter if needed - styleKeySize += 2; -@@ -185,66 +185,56 @@ skgpu::UniqueKey GenerateClipMaskKey(uint32_t stackRecordID, - skgpu::UniqueKey maskKey; - // if the element list is too large we just use the stackRecordID - if (elementsForMask->size() <= kMaxShapeCountForKey) { -- constexpr int kXformKeySize = 5; -- int keySize = 0; -- bool canCreateKey = true; -- // Iterate through to get key size and see if we can create a key at all -+ static constexpr int kXformKeySize = 5; -+ uint16_t keySize = includeBounds ? 2 : 0; -+ // Iterate through to get key size; given kMaxShapeCountForKey and Shape's own key size -+ // limitations, this should always fit safely within a 16-bit number - for (int i = 0; i < elementsForMask->size(); ++i) { -- int shapeKeySize = (*elementsForMask)[i]->fShape.keySize(); -- if (shapeKeySize < 0) { -- canCreateKey = false; -- break; -- } -- keySize += kXformKeySize + shapeKeySize; -+ keySize += kXformKeySize + (*elementsForMask)[i]->fShape.keySize(); - } -- if (canCreateKey) { -- if (includeBounds) { -- keySize += 2; -- } -- skgpu::UniqueKey::Builder builder(&maskKey, kDomain, keySize, -- "Clip Path Mask"); -- int elementKeyIndex = 0; -- Rect unclippedBounds = Rect::InfiniteInverted(); -- for (int i = 0; i < elementsForMask->size(); ++i) { -- const ClipStack::Element* element = (*elementsForMask)[i]; -- -- // Add transform key and get packed fractional translation bits -- uint32_t fracBits = add_transform_key(&builder, -- elementKeyIndex, -- element->fLocalToDevice); -- uint32_t opBits = static_cast(element->fOp); -- builder[elementKeyIndex + 4] = fracBits | (opBits << 16); -- -- const Shape& shape = element->fShape; -- shape.writeKey(&builder[elementKeyIndex + kXformKeySize], -- /*includeInverted=*/true); -- -- elementKeyIndex += kXformKeySize + shape.keySize(); -- -- Rect transformedBounds = element->fLocalToDevice.mapRect(element->fShape.bounds()); -- unclippedBounds.join(transformedBounds); -- } -- -- // The keyBounds are the maskDeviceBounds relative to the full transformed mask. We use -- // this to ensure we capture the situation where the maskDeviceBounds are equal in two -- // cases but actually enclose different regions of the full mask due to an integer -- // translation (which is not captured in the key) in the element transforms. -- *keyBounds = maskDeviceBounds.makeOffset(-unclippedBounds.left(), -- -unclippedBounds.top()); -- -- if (includeBounds) { -- SkASSERT(SkTFitsIn(keyBounds->left())); -- SkASSERT(SkTFitsIn(keyBounds->top())); -- SkASSERT(SkTFitsIn(keyBounds->right())); -- SkASSERT(SkTFitsIn(keyBounds->bottom())); -- -- builder[elementKeyIndex] = keyBounds->left() | (keyBounds->top() << 16); -- builder[elementKeyIndex+1] = keyBounds->right() | (keyBounds->bottom() << 16); -- } -- -- *usesPathKey = true; -- return maskKey; -+ -+ skgpu::UniqueKey::Builder builder(&maskKey, kDomain, keySize, "Clip Path Mask"); -+ int elementKeyIndex = 0; -+ Rect unclippedBounds = Rect::InfiniteInverted(); -+ for (int i = 0; i < elementsForMask->size(); ++i) { -+ const ClipStack::Element* element = (*elementsForMask)[i]; -+ -+ // Add transform key and get packed fractional translation bits -+ uint32_t fracBits = add_transform_key(&builder, -+ elementKeyIndex, -+ element->fLocalToDevice); -+ uint32_t opBits = static_cast(element->fOp); -+ builder[elementKeyIndex + 4] = fracBits | (opBits << 16); -+ -+ const Shape& shape = element->fShape; -+ shape.writeKey(&builder[elementKeyIndex + kXformKeySize], -+ /*includeInverted=*/true); -+ -+ elementKeyIndex += kXformKeySize + shape.keySize(); -+ -+ Rect transformedBounds = element->fLocalToDevice.mapRect(element->fShape.bounds()); -+ unclippedBounds.join(transformedBounds); -+ } -+ -+ // The keyBounds are the maskDeviceBounds relative to the full transformed mask. We use -+ // this to ensure we capture the situation where the maskDeviceBounds are equal in two -+ // cases but actually enclose different regions of the full mask due to an integer -+ // translation (which is not captured in the key) in the element transforms. -+ *keyBounds = maskDeviceBounds.makeOffset(-unclippedBounds.left(), -+ -unclippedBounds.top()); -+ -+ if (includeBounds) { -+ SkASSERT(SkTFitsIn(keyBounds->left())); -+ SkASSERT(SkTFitsIn(keyBounds->top())); -+ SkASSERT(SkTFitsIn(keyBounds->right())); -+ SkASSERT(SkTFitsIn(keyBounds->bottom())); -+ -+ builder[elementKeyIndex] = keyBounds->left() | (keyBounds->top() << 16); -+ builder[elementKeyIndex+1] = keyBounds->right() | (keyBounds->bottom() << 16); - } -+ -+ *usesPathKey = true; -+ return maskKey; - } - - // Either we have too many elements or at least one shape can't create a key -diff --git a/src/gpu/graphite/ResourceProvider.cpp b/src/gpu/graphite/ResourceProvider.cpp -index cd67a8af6fe60c2239dc6cfc7adaa8604ef3743a..80ce839d942b96f6ba7eb0456881a986accfe145 100644 ---- a/src/gpu/graphite/ResourceProvider.cpp -+++ b/src/gpu/graphite/ResourceProvider.cpp -@@ -177,7 +177,7 @@ sk_sp ResourceProvider::findOrCreateCompatibleSampler(const SamplerDesc - // immutable sampler details into the SamplerDesc, so there is no need to delegate to Caps - // to create a specific key. - const SkSpan& samplerData = samplerDesc.asSpan(); -- GraphiteResourceKey::Builder builder(&key, kType, samplerData.size()); -+ GraphiteResourceKey::Builder builder(&key, kType, SkTo(samplerData.size())); - - for (size_t i = 0; i < samplerData.size(); i++) { - builder[i] = samplerData[i]; -@@ -231,8 +231,8 @@ sk_sp ResourceProvider::findOrCreateBuffer( - // For the key we need ((sizeof(size_t) + (sizeof(uint32_t) - 1)) / (sizeof(uint32_t)) - // uint32_t's for the size and one uint32_t for the rest. - static_assert(sizeof(uint32_t) == 4); -- static const int kSizeKeyNum32DataCnt = (sizeof(size_t) + 3) / 4; -- static const int kKeyNum32DataCnt = kSizeKeyNum32DataCnt + 1; -+ static const uint16_t kSizeKeyNum32DataCnt = (sizeof(size_t) + 3) / 4; -+ static const uint16_t kKeyNum32DataCnt = kSizeKeyNum32DataCnt + 1; - - SkASSERT(static_cast(type) < (1u << 4)); - SkASSERT(static_cast(accessPattern) < (1u << 2)); -diff --git a/src/gpu/graphite/dawn/DawnCaps.cpp b/src/gpu/graphite/dawn/DawnCaps.cpp -index 3717790e1413401c0fbf12ff4cebd31132153ffd..1c281e3e7fd0299fb14d7fa8c763690bf68bae6b 100644 ---- a/src/gpu/graphite/dawn/DawnCaps.cpp -+++ b/src/gpu/graphite/dawn/DawnCaps.cpp -@@ -1016,7 +1016,7 @@ uint32_t DawnCaps::getRenderPassDescKeyForPipeline(const RenderPassDesc& renderP - loadResolveAttachmentKey; - } - --static constexpr int kDawnGraphicsPipelineKeyData32Count = 4; -+static constexpr uint16_t kDawnGraphicsPipelineKeyData32Count = 4; - - UniqueKey DawnCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc, - const RenderPassDesc& renderPassDesc) const { -@@ -1234,7 +1234,7 @@ void DawnCaps::buildKeyForTexture(SkISize dimensions, - SkASSERT(static_cast(dawnInfo.fUsage) < (1u << 28)); // usage is remaining 28 bits - - // We need two uint32_ts for dimensions, 1 for format, and 1 for the rest of the key; -- int num32DataCnt = 2 + 1 + 1; -+ uint16_t num32DataCnt = 2 + 1 + 1; - bool hasYcbcrInfo = false; - #if !defined(__EMSCRIPTEN__) - // If we are using ycbcr texture/sampling, more key information is needed. -diff --git a/src/gpu/graphite/geom/AnalyticBlurMask.cpp b/src/gpu/graphite/geom/AnalyticBlurMask.cpp -index 97f38ba054f66249d70c739cea0318f4d3e30203..5a118bf8b1792be4400a5a43db2d936366157fd0 100644 ---- a/src/gpu/graphite/geom/AnalyticBlurMask.cpp -+++ b/src/gpu/graphite/geom/AnalyticBlurMask.cpp -@@ -375,7 +375,7 @@ std::optional AnalyticBlurMask::MakeRRect(Recorder* recorder, - static const UniqueKey::Domain kRRectBlurDomain = UniqueKey::GenerateDomain(); - UniqueKey key; - { -- static constexpr int kKeySize = sizeof(DerivedParams) / sizeof(uint32_t); -+ static constexpr uint16_t kKeySize = sizeof(DerivedParams) / sizeof(uint32_t); - static_assert(SkIsAlign4(sizeof(DerivedParams))); - // TODO: We should discretize the sigma to perceptibly meaningful changes to the table, - // as well as the underlying the round rect geometry. -diff --git a/src/gpu/graphite/geom/Shape.cpp b/src/gpu/graphite/geom/Shape.cpp -index 29898fb00507aa64317ffd78354f36a18ca0a7b0..2465dcfb9fc92b678e67520e7b0e104d8514c147 100644 ---- a/src/gpu/graphite/geom/Shape.cpp -+++ b/src/gpu/graphite/geom/Shape.cpp -@@ -183,8 +183,8 @@ void write_path_key_from_data(const SkPath& path, uint32_t* origKey) { - } - } // anonymous namespace - --int Shape::keySize() const { -- int count = 1; // Every key has the state flags from the Shape -+uint16_t Shape::keySize() const { -+ uint16_t count = 1; // Every key has the state flags from the Shape - switch(this->type()) { - case Type::kLine: - static_assert(0 == sizeof(skvx::float4) % sizeof(uint32_t)); -@@ -207,7 +207,7 @@ int Shape::keySize() const { - if (!this->path().isEmpty()) { - int dataKeySize = path_key_from_data_size(this->path()); - if (dataKeySize >= 0) { -- count += dataKeySize; -+ count += SkTo(dataKeySize); - } else { - count++; // Just adds the gen ID. - } -diff --git a/src/gpu/graphite/geom/Shape.h b/src/gpu/graphite/geom/Shape.h -index 8c02945b7090779385a82aa4a8d257dad758e331..30dd8fffb797aee0c8a85093f5d5cdb97ef1a0fa 100644 ---- a/src/gpu/graphite/geom/Shape.h -+++ b/src/gpu/graphite/geom/Shape.h -@@ -184,7 +184,7 @@ public: - /** - * Gets the size of the key for the shape represented by this Shape. - */ -- int keySize() const; -+ uint16_t keySize() const; - - /** - * Writes keySize() bytes into the provided pointer. Assumes that there is enough -diff --git a/src/gpu/graphite/mtl/MtlCaps.mm b/src/gpu/graphite/mtl/MtlCaps.mm -index 7816ca699def160c1aa56afb28463d3c9d77926f..e5939af8fef877c297e98195e111860c88b0e876 100644 ---- a/src/gpu/graphite/mtl/MtlCaps.mm -+++ b/src/gpu/graphite/mtl/MtlCaps.mm -@@ -949,7 +949,7 @@ MTLPixelFormat format_from_compression(SkTextureCompressionType compression) { - return {formatInfo.fColorTypeInfos.get(), formatInfo.fColorTypeInfoCount}; - } - --static constexpr int kMtlGraphicsPipelineKeyData32Count = 4; -+static constexpr uint16_t kMtlGraphicsPipelineKeyData32Count = 4; - - UniqueKey MtlCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc, - const RenderPassDesc& renderPassDesc) const { -@@ -1193,7 +1193,7 @@ MTLPixelFormat format_from_compression(SkTextureCompressionType compression) { - SkASSERT(static_cast(isFBOnly) < (1u << 1)); - - // We need two uint32_ts for dimensions, 2 for format, and 1 for the rest of the key; -- static int kNum32DataCnt = 2 + 2 + 1; -+ static uint16_t kNum32DataCnt = 2 + 2 + 1; - - GraphiteResourceKey::Builder builder(key, type, kNum32DataCnt); - -diff --git a/src/gpu/graphite/vk/VulkanCaps.cpp b/src/gpu/graphite/vk/VulkanCaps.cpp -index 799d90b03c54cee89b24281e25c46813adef5046..f5ae0b882af66050b3e90c121675ab1b3a4ec870 100644 ---- a/src/gpu/graphite/vk/VulkanCaps.cpp -+++ b/src/gpu/graphite/vk/VulkanCaps.cpp -@@ -2087,7 +2087,7 @@ bool VulkanCaps::msaaTextureRenderToSingleSampledSupport(const TextureInfo& info - - // 4 uint32s for the render step id, paint id, compatible render pass description, and write - // swizzle. --static constexpr int kPipelineKeyData32Count = 4; -+static constexpr uint16_t kPipelineKeyData32Count = 4; - - static constexpr int kPipelineKeyRenderStepIDIndex = 0; - static constexpr int kPipelineKeyPaintParamsIDIndex = 1; -@@ -2173,15 +2173,15 @@ void VulkanCaps::buildKeyForTexture(SkISize dimensions, - SkASSERT(vkInfo.fAspectMask < (1u << 11)); // aspectMask is bits 8 - 19 - - // We need two uint32_ts for dimensions and 3 for miscellaneous information. -- static constexpr int kNum32DimensionDataCnt = 2; -- static constexpr int kNum32MiscDataCnt = 3; -+ static constexpr uint16_t kNum32DimensionDataCnt = 2; -+ static constexpr uint16_t kNum32MiscDataCnt = 3; - // Non-YCbCr formats need 1 int for format. - // YCbCr conversion needs 1 int for non-format flags, and a 64-bit format (external or regular). -- static constexpr int kNum32FormatDataCntNoYcbcr = 1; -- static constexpr int kNum32FormatDataCntYcbcr = 3; -+ static constexpr uint16_t kNum32FormatDataCntNoYcbcr = 1; -+ static constexpr uint16_t kNum32FormatDataCntYcbcr = 3; - - const VulkanYcbcrConversionInfo& ycbcrInfo = vkInfo.fYcbcrConversionInfo; -- const int num32DataCnt = -+ const uint16_t num32DataCnt = - kNum32DimensionDataCnt + kNum32MiscDataCnt + - (ycbcrInfo.isValid() ? kNum32FormatDataCntYcbcr : kNum32FormatDataCntNoYcbcr); - -diff --git a/src/gpu/graphite/vk/VulkanResourceProvider.cpp b/src/gpu/graphite/vk/VulkanResourceProvider.cpp -index bb2f400250c569b73120f857133cafcca51c1c77..f66c6d0d2cf8c8bb4b34c7479445185c3a3c7cf4 100644 ---- a/src/gpu/graphite/vk/VulkanResourceProvider.cpp -+++ b/src/gpu/graphite/vk/VulkanResourceProvider.cpp -@@ -218,7 +218,7 @@ GraphiteResourceKey build_desc_set_key(const SkSpan& requestedDe - } - - GraphiteResourceKey key; -- GraphiteResourceKey::Builder builder(&key, kType, keyData.size()); -+ GraphiteResourceKey::Builder builder(&key, kType, SkTo(keyData.size())); - - for (int i = 0; i < keyData.size(); i++) { - builder[i] = keyData[i]; -@@ -548,7 +548,7 @@ sk_sp VulkanResourceProvider::findOrCreateCompatibleYcbcr - GraphiteResourceKey key; - { - static const ResourceType kType = GraphiteResourceKey::GenerateResourceType(); -- static constexpr int kKeySize = 3; -+ static constexpr uint16_t kKeySize = 3; - - GraphiteResourceKey::Builder builder(&key, kType, kKeySize); - ImmutableSamplerInfo packedInfo = VulkanYcbcrConversion::ToImmutableSamplerInfo(ycbcrInfo); -diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp -index 68da13ca9b048cd0d1dc9b62090c17793a11b3a1..9c3ef544ffda6ba72c2972f020ac2a06232484b6 100644 ---- a/src/utils/SkShadowUtils.cpp -+++ b/src/utils/SkShadowUtils.cpp -@@ -358,7 +358,10 @@ public: - const SkMatrix& viewMatrix() const { return *fViewMatrix; } - #if defined(SK_GANESH) - /** Negative means the vertices should not be cached for this path. */ -- int keyBytes() const { return fShapeForKey.unstyledKeySize() * sizeof(uint32_t); } -+ int keyBytes() const { -+ return fShapeForKey.hasUnstyledKey() ? fShapeForKey.unstyledKeySize() * sizeof(uint32_t) -+ : -1; -+ } - void writeKey(void* key) const { - fShapeForKey.writeUnstyledKey(reinterpret_cast(key)); - }