[compiler-rt] [CopyProf] Implement minimal CopyProf runtime. (PR #223458)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 12:07:29 PDT 2026
================
@@ -0,0 +1,112 @@
+//===-- copyprof_shadow.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file implements the shadow memory management for CopyProf, tracking
+/// the copy status and modification state of application memory.
+///
+//===----------------------------------------------------------------------===//
+
+#include "copyprof_shadow.h"
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __copyprof {
+namespace {
+
+constexpr uptr kBitsPerShadowByte = 8;
+static_assert(
+ 1 << kShadowScale == kBitsPerShadowByte,
+ "CopyProf tracks 1 bit per application byte (8 bits per shadow byte)");
+
+// Tracks whether application memory is marked as a copy.
+ShadowMemory g_copy_shadow;
+
+// Returns a mask with bits [`start_bit`, `end_bit`) set.
+unsigned char BitMask(uptr start_bit, uptr end_bit) {
+ CHECK_LE(start_bit, end_bit);
+ return static_cast<unsigned char>((1 << end_bit) - (1 << start_bit));
+}
+
+// Whether bits [`start_bit`, `end_bit`) of `shadow_byte` are all set.
+bool AllBitsSet(unsigned char shadow_byte, uptr start_bit, uptr end_bit) {
+ const unsigned char mask = BitMask(start_bit, end_bit);
+ return (shadow_byte & mask) == mask;
+}
+
+// Sets (or clears) bits [`start_bit`, `end_bit`) of `*shadow_byte`.
+void SetBits(unsigned char* shadow_byte, uptr start_bit, uptr end_bit,
+ bool is_copy) {
+ const unsigned char mask = BitMask(start_bit, end_bit);
+ if (is_copy)
+ *shadow_byte |= mask;
+ else
+ *shadow_byte &= static_cast<unsigned char>(~mask);
+}
+
+uptr BytesToShadowBits(uptr num_bytes) {
+ // Each application byte maps to one shadow bit.
+ return num_bytes;
+}
+
+} // namespace
+
+void InitializeShadowMemory() {
+ g_copy_shadow = ShadowMemory::Create("copyprof");
+}
+
+void MarkApplicationMemory(const void* app_addr, uptr num_bytes, bool is_copy) {
+ CHECK_GT(num_bytes, 0);
+ const uptr addr = reinterpret_cast<uptr>(app_addr);
+ unsigned char* shadow =
+ reinterpret_cast<unsigned char*>(g_copy_shadow.MemToShadow(addr));
+
+ // An application range need not start on a shadow byte boundary, so it is
+ // updated in three steps: the leading (possibly partial) shadow byte, the
+ // whole shadow bytes in the middle, and the trailing partial byte.
+ uptr num_shadow_bits = BytesToShadowBits(num_bytes);
+ if (uptr start_bit = addr % kBitsPerShadowByte; start_bit > 0) {
+ uptr end_bit =
+ start_bit + Min(kBitsPerShadowByte - start_bit, num_shadow_bits);
+ SetBits(shadow++, start_bit, end_bit, is_copy);
+ num_shadow_bits -= end_bit - start_bit;
+ }
+ if (uptr full_bytes = num_shadow_bits / kBitsPerShadowByte; full_bytes > 0) {
+ internal_memset(shadow, is_copy ? 0xFF : 0, full_bytes);
+ shadow += full_bytes;
+ num_shadow_bits -= full_bytes * kBitsPerShadowByte;
+ }
+ if (num_shadow_bits > 0)
+ SetBits(shadow, /*start_bit=*/0, num_shadow_bits, is_copy);
+}
+
+bool IsMarkedAsCopy(const void* app_addr, uptr num_bytes) {
----------------
newgre wrote:
I could factor this out into a "TraverseShadowMemory" function template that would accept two lambdas, one for processing partial shadow bytes, the other for processing full shadow bytes, but at that point I'm unsure whether that's a readability gain over a couple lines of duplicated code? Want me to make that change or did you have something else in mind?
https://github.com/llvm/llvm-project/pull/223458
More information about the llvm-commits
mailing list