chromium-add-atomicops.patch (upstream commit d29b01737a841b5627249d50f007dcdc7e26462b) chromium-use-atomicops.patch (upstream commit 780efe38034cfdc1bdf4c74e82e7ca7c14e8ac5b) - update INSTALL.sh to generate appdata.xml from template OBS-URL: https://build.opensuse.org/package/show/network:chromium/chromium-beta?expand=0&rev=128
189 lines
6.8 KiB
Diff
189 lines
6.8 KiB
Diff
From d29b01737a841b5627249d50f007dcdc7e26462b Mon Sep 17 00:00:00 2001
|
|
From: Eugene Zemtsov <eugene@chromium.org>
|
|
Date: Thu, 19 Dec 2024 13:20:12 -0800
|
|
Subject: [PATCH] Introducing base::RelaxedAtomicWriteMemcpy
|
|
|
|
This is an analogue of `WTF::AtomicWriteMemcpy` and it should be used
|
|
for copying data into buffers owned by `SharedArrayBuffer`.
|
|
While the copy is being done, JS and WASM code can access the `dst` buffer
|
|
on a different thread. The data observed by JS may not be consistent
|
|
from application point of view (which is always the case with
|
|
`SharedArrayBuffer`), but it won't trigger C++ UB and won't upset TSAN.
|
|
Reads from the `src` buffer are not atomic and should be `src` access
|
|
should be synchronized via other means.
|
|
|
|
Bug: 340606792
|
|
Change-Id: I95fd92d344dce4d463fa281b68b266bb0a8053a8
|
|
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6065639
|
|
Reviewed-by: Shu-yu Guo <syg@chromium.org>
|
|
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
|
Reviewed-by: Gabriel Charette <gab@chromium.org>
|
|
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
|
|
Cr-Commit-Position: refs/heads/main@{#1398823}
|
|
|
|
diff --git a/base/BUILD.gn b/base/BUILD.gn
|
|
index 0b0d3c262a1d4..97bec1f29bc3b 100644
|
|
--- a/base/BUILD.gn
|
|
+++ b/base/BUILD.gn
|
|
@@ -186,6 +186,7 @@ component("base") {
|
|
"at_exit.h",
|
|
"atomic_ref_count.h",
|
|
"atomic_sequence_num.h",
|
|
+ "atomicops.cc",
|
|
"atomicops.h",
|
|
"atomicops_internals_atomicword_compat.h",
|
|
"atomicops_internals_portable.h",
|
|
diff --git a/base/atomicops.cc b/base/atomicops.cc
|
|
new file mode 100644
|
|
index 0000000000000..7b6aca4d6c3c3
|
|
--- /dev/null
|
|
+++ b/base/atomicops.cc
|
|
@@ -0,0 +1,65 @@
|
|
+// Copyright 2024 The Chromium Authors
|
|
+// Use of this source code is governed by a BSD-style license that can be
|
|
+// found in the LICENSE file.
|
|
+
|
|
+#include "base/atomicops.h"
|
|
+
|
|
+#include <atomic>
|
|
+
|
|
+#include "base/memory/aligned_memory.h"
|
|
+
|
|
+namespace base::subtle {
|
|
+
|
|
+void RelaxedAtomicWriteMemcpy(base::span<uint8_t> dst,
|
|
+ base::span<const uint8_t> src) {
|
|
+ CHECK_EQ(dst.size(), src.size());
|
|
+ size_t bytes = dst.size();
|
|
+ uint8_t* dst_byte_ptr = dst.data();
|
|
+ const uint8_t* src_byte_ptr = src.data();
|
|
+ // Make sure that we can at least copy byte by byte with atomics.
|
|
+ static_assert(std::atomic_ref<uint8_t>::required_alignment == 1);
|
|
+
|
|
+ // Alignment for uintmax_t atomics that we use in the happy case.
|
|
+ constexpr size_t kDesiredAlignment =
|
|
+ std::atomic_ref<uintmax_t>::required_alignment;
|
|
+
|
|
+ // Copy byte-by-byte until `dst_byte_ptr` is not properly aligned for
|
|
+ // the happy case.
|
|
+ while (bytes > 0 && !IsAligned(dst_byte_ptr, kDesiredAlignment)) {
|
|
+ std::atomic_ref<uint8_t>(*dst_byte_ptr)
|
|
+ .store(*src_byte_ptr, std::memory_order_relaxed);
|
|
+ // SAFETY: We check above that `dst_byte_ptr` and `src_byte_ptr` point
|
|
+ // to spans of sufficient size.
|
|
+ UNSAFE_BUFFERS(++dst_byte_ptr);
|
|
+ UNSAFE_BUFFERS(++src_byte_ptr);
|
|
+ --bytes;
|
|
+ }
|
|
+
|
|
+ // Happy case where both `src_byte_ptr` and `dst_byte_ptr` are both properly
|
|
+ // aligned and the largest possible atomic is used for copying.
|
|
+ if (IsAligned(src_byte_ptr, kDesiredAlignment)) {
|
|
+ while (bytes >= sizeof(uintmax_t)) {
|
|
+ std::atomic_ref<uintmax_t>(*reinterpret_cast<uintmax_t*>(dst_byte_ptr))
|
|
+ .store(*reinterpret_cast<const uintmax_t*>(src_byte_ptr),
|
|
+ std::memory_order_relaxed);
|
|
+ // SAFETY: We check above that `dst_byte_ptr` and `src_byte_ptr` point
|
|
+ // to spans of sufficient size.
|
|
+ UNSAFE_BUFFERS(dst_byte_ptr += sizeof(uintmax_t));
|
|
+ UNSAFE_BUFFERS(src_byte_ptr += sizeof(uintmax_t));
|
|
+ bytes -= sizeof(uintmax_t);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Copy what's left after the happy-case byte-by-byte.
|
|
+ while (bytes > 0) {
|
|
+ std::atomic_ref<uint8_t>(*dst_byte_ptr)
|
|
+ .store(*src_byte_ptr, std::memory_order_relaxed);
|
|
+ // SAFETY: We check above that `dst_byte_ptr` and `src_byte_ptr` point
|
|
+ // to spans of sufficient size.
|
|
+ UNSAFE_BUFFERS(++dst_byte_ptr);
|
|
+ UNSAFE_BUFFERS(++src_byte_ptr);
|
|
+ --bytes;
|
|
+ }
|
|
+}
|
|
+
|
|
+} // namespace base::subtle
|
|
diff --git a/base/atomicops.h b/base/atomicops.h
|
|
index 47a10e65e7ac7..33b17dae4aaa9 100644
|
|
--- a/base/atomicops.h
|
|
+++ b/base/atomicops.h
|
|
@@ -51,6 +51,9 @@
|
|
// - libstdc++: captures bits/c++config.h for __GLIBCXX__
|
|
#include <cstddef>
|
|
|
|
+#include "base/base_export.h"
|
|
+#include "base/compiler_specific.h"
|
|
+#include "base/containers/span.h"
|
|
#include "build/build_config.h"
|
|
|
|
namespace base {
|
|
@@ -139,6 +142,28 @@ Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
|
|
Atomic64 Acquire_Load(volatile const Atomic64* ptr);
|
|
#endif // ARCH_CPU_64_BITS
|
|
|
|
+// Copies non-overlapping spans of the same size. Writes are done using C++
|
|
+// atomics with `std::memory_order_relaxed`.
|
|
+//
|
|
+// This is an analogue of `WTF::AtomicWriteMemcpy` and it should be used
|
|
+// for copying data into buffers that are accessible from another
|
|
+// thread while the copy is being done. The buffer will appear inconsistent,
|
|
+// but it won't trigger C++ UB and won't upset TSAN. The end of copy needs to
|
|
+// be signaled through a synchronization mechanism like fence, after
|
|
+// which the `dst` buffer will be observed as consistent.
|
|
+//
|
|
+// Notable example is a buffer owned by `SharedArrayBuffer`.
|
|
+// While the copy is being done, JS and WASM code can access the `dst` buffer
|
|
+// on a different thread. The data observed by JS may not be consistent
|
|
+// from application point of view (which is always the case with
|
|
+// `SharedArrayBuffer`).
|
|
+//
|
|
+// Reads from the `src` buffer are not atomic and `src` access
|
|
+// should be synchronized via other means.
|
|
+// More info: crbug.com/340606792
|
|
+BASE_EXPORT void RelaxedAtomicWriteMemcpy(base::span<uint8_t> dst,
|
|
+ base::span<const uint8_t> src);
|
|
+
|
|
} // namespace subtle
|
|
} // namespace base
|
|
|
|
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc
|
|
index b494bd136bc15..1227dc3b2e053 100644
|
|
--- a/base/atomicops_unittest.cc
|
|
+++ b/base/atomicops_unittest.cc
|
|
@@ -6,7 +6,9 @@
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
+
|
|
#include <type_traits>
|
|
+#include <vector>
|
|
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
@@ -239,3 +241,24 @@ TEST(AtomicOpsTest, Load) {
|
|
TestLoad<base::subtle::Atomic32>();
|
|
TestLoad<base::subtle::AtomicWord>();
|
|
}
|
|
+
|
|
+TEST(AtomicOpsTest, RelaxedAtomicWriteMemcpy) {
|
|
+ std::vector<uint8_t> src(17);
|
|
+ for (size_t i = 0; i < src.size(); i++) {
|
|
+ src[i] = i + 1;
|
|
+ }
|
|
+
|
|
+ for (size_t i = 0; i < src.size(); i++) {
|
|
+ std::vector<uint8_t> dst(src.size());
|
|
+ size_t bytes_to_copy = src.size() - i;
|
|
+ base::subtle::RelaxedAtomicWriteMemcpy(
|
|
+ base::span(dst).first(bytes_to_copy),
|
|
+ base::span(src).subspan(i, bytes_to_copy));
|
|
+ for (size_t j = 0; j < bytes_to_copy; j++) {
|
|
+ EXPECT_EQ(src[i + j], dst[j]);
|
|
+ }
|
|
+ for (size_t j = bytes_to_copy; j < dst.size(); j++) {
|
|
+ EXPECT_EQ(0, dst[j]);
|
|
+ }
|
|
+ }
|
|
+}
|