[llvm-branch-commits] [clang] [compiler-rt] [CopyProf] Intercept new/delete and track per-object cost. (PR #235455)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Oct 25 07:40:08 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: newgre
<details>
<summary>Changes</summary>
This intercepts the C++ `new` and `delete` operators, so that all
heap memory owned by a copy is tracked.
Using per-object state tracking, reports now tell the user how much
accumulated memory a copy is worth and whether it allocated.
This is useful for filtering of reports.
RFC: https://discourse.llvm.org/t/rfc-copysanitizer-csan-detecting-unneccessary-object-copies-at-runtime/91038
Stack: #<!-- -->232851 → #<!-- -->235453 → #<!-- -->235454 → #<!-- -->235455 (this PR)
---
Patch is 25.62 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/235455.diff
13 Files Affected:
- (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+4-1)
- (modified) clang/test/Driver/fcopyprof.cpp (+5-4)
- (modified) compiler-rt/lib/copyprof/CMakeLists.txt (+23)
- (modified) compiler-rt/lib/copyprof/copyprof.cpp (+17-5)
- (modified) compiler-rt/lib/copyprof/copyprof_allocator.cpp (+7-5)
- (added) compiler-rt/lib/copyprof/copyprof_new_delete.cpp (+139)
- (added) compiler-rt/lib/copyprof/copyprof_per_object_state.cpp (+70)
- (added) compiler-rt/lib/copyprof/copyprof_per_object_state.h (+44)
- (modified) compiler-rt/lib/copyprof/copyprof_reporting.cpp (+1-1)
- (modified) compiler-rt/lib/copyprof/copyprof_reporting.h (+3-2)
- (modified) compiler-rt/lib/copyprof/copyprof_state.cpp (+10)
- (modified) compiler-rt/lib/copyprof/copyprof_state.h (+15)
- (modified) compiler-rt/lib/copyprof/tests/copyprof_state_test.cpp (+102)
``````````diff
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 7c832ef405fa51..ef83d55f8344ad 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1795,8 +1795,11 @@ collectSanitizerRuntimes(Compilation &C, const ToolChain &TC,
StaticRuntimes.push_back("dfsan");
if (SanArgs.needsLsanRt())
StaticRuntimes.push_back("lsan");
- if (SanArgs.needsCopyProfRt())
+ if (SanArgs.needsCopyProfRt()) {
StaticRuntimes.push_back("copyprof");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("copyprof_cxx");
+ }
if (SanArgs.needsMsanRt()) {
StaticRuntimes.push_back("msan");
if (SanArgs.linkCXXRuntimes())
diff --git a/clang/test/Driver/fcopyprof.cpp b/clang/test/Driver/fcopyprof.cpp
index 2ac70d3349116e..8e3b5781385770 100644
--- a/clang/test/Driver/fcopyprof.cpp
+++ b/clang/test/Driver/fcopyprof.cpp
@@ -1,13 +1,14 @@
// Test driver flags for CopyProf instrumentation and runtime linking.
// Basic C and C++ invocations:
-// RUN: %clang --target=x86_64-linux-gnu -fcopyprof %s -### 2>&1 | FileCheck %s
-// RUN: %clangxx --target=x86_64-linux-gnu -fcopyprof %s -### 2>&1 | FileCheck %s
+// RUN: %clang --target=x86_64-linux-gnu -fcopyprof %s -### 2>&1 | FileCheck %s --implicit-check-not=libclang_rt.copyprof_cxx
+// RUN: %clangxx --target=x86_64-linux-gnu -fcopyprof %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-CXX
// CHECK: "-cc1" {{.*}} "-fcopyprof"
-// CHECK: ld{{.*}}libclang_rt.copyprof
+// CHECK: ld{{.*}}libclang_rt.copyprof{{[-.]}}
+// CHECK-CXX-SAME: libclang_rt.copyprof_cxx
// Re-enabling after -fno-copyprof:
-// RUN: %clangxx --target=x86_64-linux-gnu -fcopyprof -fno-copyprof -fcopyprof %s -### 2>&1 | FileCheck %s
+// RUN: %clangxx --target=x86_64-linux-gnu -fcopyprof -fno-copyprof -fcopyprof %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-CXX
// Custom static size threshold (and last-flag-wins behavior):
// RUN: %clangxx --target=x86_64-linux-gnu -fcopyprof -fcopyprof-static-size-threshold=32 %s -### 2>&1 | FileCheck %s --check-prefix=THRESHOLD32
diff --git a/compiler-rt/lib/copyprof/CMakeLists.txt b/compiler-rt/lib/copyprof/CMakeLists.txt
index 1d925167f58934..dbbf9ea7a82911 100644
--- a/compiler-rt/lib/copyprof/CMakeLists.txt
+++ b/compiler-rt/lib/copyprof/CMakeLists.txt
@@ -7,18 +7,24 @@ set(COPYPROF_SOURCES
copyprof_interceptors_memintrinsics.cpp
copyprof_malloc_linux.cpp
copyprof_preinit.cpp
+ copyprof_per_object_state.cpp
copyprof_reporting.cpp
copyprof_shadow.cpp
copyprof_stack.cpp
copyprof_state.cpp
)
+set(COPYPROF_CXX_SOURCES
+ copyprof_new_delete.cpp
+)
+
set(COPYPROF_HEADERS
copyprof_allocator.h
copyprof_interceptors.h
copyprof_interceptors_memintrinsics.h
copyprof_interface_internal.h
copyprof_internal.h
+ copyprof_per_object_state.h
copyprof_reporting.h
copyprof_shadow.h
copyprof_state.h
@@ -37,6 +43,12 @@ add_compiler_rt_object_libraries(RTCopyProf
ADDITIONAL_HEADERS ${COPYPROF_HEADERS}
CFLAGS ${COPYPROF_CFLAGS}
DEFS ${COPYPROF_COMMON_DEFINITIONS})
+add_compiler_rt_object_libraries(RTCopyProf_cxx
+ ARCHS ${COPYPROF_SUPPORTED_ARCH}
+ SOURCES ${COPYPROF_CXX_SOURCES}
+ ADDITIONAL_HEADERS ${COPYPROF_HEADERS}
+ CFLAGS ${COPYPROF_CFLAGS}
+ DEFS ${COPYPROF_COMMON_DEFINITIONS})
# Build CopyProf runtimes shipped with Clang.
add_compiler_rt_component(copyprof)
@@ -58,12 +70,23 @@ add_compiler_rt_runtime(clang_rt.copyprof
DEFS ${COPYPROF_COMMON_DEFINITIONS}
PARENT_TARGET copyprof)
+add_compiler_rt_runtime(clang_rt.copyprof_cxx
+ STATIC
+ ARCHS ${COPYPROF_SUPPORTED_ARCH}
+ OBJECT_LIBS RTCopyProf_cxx
+ CFLAGS ${COPYPROF_CFLAGS}
+ DEFS ${COPYPROF_COMMON_DEFINITIONS}
+ PARENT_TARGET copyprof)
+
if(SANITIZER_USE_SYMBOLS)
foreach(arch ${COPYPROF_SUPPORTED_ARCH})
add_sanitizer_rt_symbols(clang_rt.copyprof
ARCHS ${arch}
PARENT_TARGET copyprof
EXTRA copyprof.syms.extra)
+ add_sanitizer_rt_symbols(clang_rt.copyprof_cxx
+ ARCHS ${arch}
+ PARENT_TARGET copyprof)
endforeach()
endif()
diff --git a/compiler-rt/lib/copyprof/copyprof.cpp b/compiler-rt/lib/copyprof/copyprof.cpp
index 0dddf05af70aa2..29d70e022704b3 100644
--- a/compiler-rt/lib/copyprof/copyprof.cpp
+++ b/compiler-rt/lib/copyprof/copyprof.cpp
@@ -14,6 +14,7 @@
#include "copyprof_allocator.h"
#include "copyprof_interceptors.h"
#include "copyprof_interface_internal.h"
+#include "copyprof_per_object_state.h"
#include "copyprof_reporting.h"
#include "copyprof_shadow.h"
#include "copyprof_state.h"
@@ -53,6 +54,7 @@ static void Initialize() {
InitializeCommonFlags();
InitializeInterceptors();
InitializeShadowMemory();
+ InitializePerObjectTracking();
InitializeCopyProfAllocator();
copyprof_init_is_running = false;
copyprof_is_initialized = true;
@@ -91,7 +93,14 @@ static void MarkConstructedObject(const void* this_ptr, uptr obj_size) {
static void CopyMemberFunctionEnter(const void* this_ptr, uptr obj_size) {
MaybeUpdateSmfContext(SmfContext::COPY);
- if (__copyprof_state.copy_nesting_level++ == 0) {
+ // Currently, only top-level copies are reported, so only top-level objects
+ // get per-object state which is then removed when the corresponding top-level
+ // d'tor exits. A nested object copy is not individually marked as a copy and
+ // is typically destroyed by a nested d'tor, so its state would never be
+ // removed (from the object state map).
+ if (__copyprof_state.copy_nesting_level++ == 0 &&
+ __copyprof_state.smf_context == SmfContext::COPY) {
+ InitPerObjectState(this_ptr, obj_size);
__copyprof_state.current_this_ptr = this_ptr;
}
}
@@ -161,10 +170,13 @@ void __copyprof_dtor_exit_callback(const void* this_ptr, uptr obj_size) {
__copyprof_state.is_transitive_copy &= IsMarkedAsCopy(this_ptr, obj_size);
if (__copyprof_state.destruct_nesting_level == 0 &&
__copyprof_state.is_transitive_copy) {
- // TODO: Dynamic allocation tracking via malloc/new interception will be
- // added in a subsequent patch. For now, did_allocate is set to true.
- LogCopyProfReport(GET_CALLER_PC(), GET_CURRENT_FRAME(), obj_size,
- /*did_allocate=*/true);
+ LogCopyProfReport(GET_CALLER_PC(), GET_CURRENT_FRAME(),
+ GetPerObjectTrackedSize(this_ptr),
+ GetPerObjectDidAllocate(this_ptr));
+ }
+ // Clean up per-object state when top-level destructor exits.
+ if (__copyprof_state.destruct_nesting_level == 0) {
+ RemovePerObjectState(this_ptr);
}
}
diff --git a/compiler-rt/lib/copyprof/copyprof_allocator.cpp b/compiler-rt/lib/copyprof/copyprof_allocator.cpp
index f854a03a4dce58..756a7266868c72 100644
--- a/compiler-rt/lib/copyprof/copyprof_allocator.cpp
+++ b/compiler-rt/lib/copyprof/copyprof_allocator.cpp
@@ -17,6 +17,7 @@
#include "copyprof_interceptors.h"
#include "copyprof_interface_internal.h"
+#include "copyprof_per_object_state.h"
#include "copyprof_shadow.h"
#include "copyprof_state.h"
#include "sanitizer_common/sanitizer_allocator.h"
@@ -152,9 +153,10 @@ struct CopyProfAllocator {
ReportOutOfMemory(size, &stack);
}
GetMetadata(allocated)->requested_size = size;
- MarkApplicationMemory(
- allocated, size,
- ShouldMarkNewMemoryAsCopy(__copyprof_state.smf_context));
+ SmfContext ctx = __copyprof_state.smf_context;
+ MarkApplicationMemory(allocated, size, ShouldMarkNewMemoryAsCopy(ctx));
+ if (ctx == SmfContext::COPY)
+ RecordPerObjectAllocation(__copyprof_state.current_this_ptr, size);
return allocated;
}
@@ -191,8 +193,8 @@ struct CopyProfAllocator {
}
// Implemented via `Allocate` and `Deallocate` rather than
- // `CombinedAllocator::Reallocate`, s.t. shadow memory and metadata are
- // updated as for any other (de)allocation.
+ // `CombinedAllocator::Reallocate`, s.t. shadow memory, metadata and
+ // per-object state are updated as for any other (de)allocation.
// Note that the shadow of the old memory is not carried over.
// TODO: figure out whether this assumption is a problem in practice.
void* Reallocate(void* old_ptr, uptr new_size) {
diff --git a/compiler-rt/lib/copyprof/copyprof_new_delete.cpp b/compiler-rt/lib/copyprof/copyprof_new_delete.cpp
new file mode 100644
index 00000000000000..b91c08a9249651
--- /dev/null
+++ b/compiler-rt/lib/copyprof/copyprof_new_delete.cpp
@@ -0,0 +1,139 @@
+//===-- copyprof_new_delete.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 interceptors for C++ new and delete operators, tracking
+/// dynamic object lifecycle events in the CopyProf runtime.
+///
+//===----------------------------------------------------------------------===//
+
+// Routines to intercept C and C++ (de-)allocation functions.
+
+#include <stddef.h>
+
+#include "copyprof_allocator.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_report.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
+namespace std {
+struct nothrow_t {};
+enum class align_val_t : size_t {};
+} // namespace std
+
+using namespace __copyprof;
+
+ALWAYS_INLINE
+void* OperatorNew(size_t size, std::align_val_t align, bool no_throw) {
+ void* result = CopyProfAllocate(size, static_cast<uptr>(align));
+ if (!no_throw && UNLIKELY(!result)) {
+ UNINITIALIZED BufferedStackTrace stack;
+ stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),
+ /*context=*/nullptr, common_flags()->fast_unwind_on_fatal);
+ ReportOutOfMemory(size, &stack);
+ }
+ return result;
+}
+
+ALWAYS_INLINE
+void OperatorDelete(void* ptr, size_t size, std::align_val_t align) {
+ CopyProfDeallocate(ptr, size, static_cast<uptr>(align));
+}
+
+INTERCEPTOR_ATTRIBUTE
+void* operator new(size_t size) {
+ return OperatorNew(size, std::align_val_t{kMinAlignment},
+ /*no_throw=*/false);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new(size_t size, std::align_val_t align) {
+ return OperatorNew(size, align, /*no_throw=*/false);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new(size_t size, std::nothrow_t const&) {
+ return OperatorNew(size, std::align_val_t{kMinAlignment},
+ /*no_throw=*/true);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new(size_t size, std::align_val_t align, std::nothrow_t const&) {
+ return OperatorNew(size, align, /*no_throw=*/true);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new[](size_t size) {
+ return OperatorNew(size, std::align_val_t{kMinAlignment},
+ /*no_throw=*/false);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new[](size_t size, std::align_val_t align) {
+ return OperatorNew(size, align, /*no_throw=*/false);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new[](size_t size, std::nothrow_t const&) {
+ return OperatorNew(size, std::align_val_t{kMinAlignment},
+ /*no_throw=*/true);
+}
+INTERCEPTOR_ATTRIBUTE
+void* operator new[](size_t size, std::align_val_t align,
+ std::nothrow_t const&) {
+ return OperatorNew(size, align, /*no_throw=*/true);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void* ptr) NOEXCEPT {
+ return OperatorDelete(ptr, /*size=*/0, std::align_val_t{0});
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void* ptr, size_t size) NOEXCEPT {
+ return OperatorDelete(ptr, size, std::align_val_t{0});
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void* ptr, std::align_val_t align) NOEXCEPT {
+ return OperatorDelete(ptr, /*size=*/0, align);
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void* ptr, std::nothrow_t const&) {
+ return OperatorDelete(ptr, /*size=*/0, std::align_val_t{0});
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void* ptr, std::align_val_t align, std::nothrow_t const&) {
+ return OperatorDelete(ptr, /*size=*/0, align);
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void* ptr, size_t size, std::align_val_t align) NOEXCEPT {
+ return OperatorDelete(ptr, size, align);
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void* ptr) NOEXCEPT {
+ return OperatorDelete(ptr, /*size=*/0, std::align_val_t{0});
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void* ptr, size_t size) NOEXCEPT {
+ return OperatorDelete(ptr, size, std::align_val_t{0});
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void* ptr, std::align_val_t align) NOEXCEPT {
+ return OperatorDelete(ptr, /*size=*/0, align);
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void* ptr, std::nothrow_t const&) {
+ return OperatorDelete(ptr, /*size=*/0, std::align_val_t{0});
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void* ptr, std::align_val_t align,
+ std::nothrow_t const&) {
+ return OperatorDelete(ptr, /*size=*/0, align);
+}
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void* ptr, size_t size,
+ std::align_val_t align) NOEXCEPT {
+ return OperatorDelete(ptr, size, align);
+}
diff --git a/compiler-rt/lib/copyprof/copyprof_per_object_state.cpp b/compiler-rt/lib/copyprof/copyprof_per_object_state.cpp
new file mode 100644
index 00000000000000..9b3608a6fcc1a3
--- /dev/null
+++ b/compiler-rt/lib/copyprof/copyprof_per_object_state.cpp
@@ -0,0 +1,70 @@
+//===-- copyprof_per_object_state.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 per-object state tracking utilities for CopyProf,
+/// managing transitive object sizes and allocation flags.
+///
+//===----------------------------------------------------------------------===//
+
+#include "copyprof_per_object_state.h"
+
+#include "copyprof_state.h"
+#include "sanitizer_common/sanitizer_dense_map.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+
+namespace __copyprof {
+namespace {
+
+using PerObjMap = DenseMap<const void*, PerObjectState>;
+
+// Global map for per-object size tracking.
+// Protected by mutex for thread-safe access.
+StaticSpinMutex g_per_obj_map_mutex;
+alignas(PerObjMap) char g_per_obj_map_placeholder[sizeof(PerObjMap)];
+PerObjMap* g_per_obj_map = nullptr;
+
+} // namespace
+
+void InitializePerObjectTracking() {
+ g_per_obj_map_mutex.Init();
+ g_per_obj_map = new (g_per_obj_map_placeholder) PerObjMap();
+}
+
+void InitPerObjectState(const void* this_ptr, uptr static_size) {
+ SpinMutexLock lock(&g_per_obj_map_mutex);
+ PerObjectState& state = (*g_per_obj_map)[this_ptr];
+ state.SetStaticSize(static_size);
+ state.did_allocate = false;
+}
+
+void RecordPerObjectAllocation(const void* this_ptr, uptr num_bytes) {
+ SpinMutexLock lock(&g_per_obj_map_mutex);
+ PerObjectState& state = (*g_per_obj_map)[this_ptr];
+ state.IncreaseTrackedSize(num_bytes);
+ state.did_allocate = true;
+}
+
+uptr GetPerObjectTrackedSize(const void* this_ptr) {
+ SpinMutexLock lock(&g_per_obj_map_mutex);
+ const auto* it = g_per_obj_map->find(this_ptr);
+ return it ? it->second.GetTrackedSize() : 0;
+}
+
+bool GetPerObjectDidAllocate(const void* this_ptr) {
+ SpinMutexLock lock(&g_per_obj_map_mutex);
+ const auto* it = g_per_obj_map->find(this_ptr);
+ return it ? it->second.did_allocate : false;
+}
+
+void RemovePerObjectState(const void* this_ptr) {
+ SpinMutexLock lock(&g_per_obj_map_mutex);
+ g_per_obj_map->erase(this_ptr);
+}
+
+} // namespace __copyprof
diff --git a/compiler-rt/lib/copyprof/copyprof_per_object_state.h b/compiler-rt/lib/copyprof/copyprof_per_object_state.h
new file mode 100644
index 00000000000000..09a694748848f1
--- /dev/null
+++ b/compiler-rt/lib/copyprof/copyprof_per_object_state.h
@@ -0,0 +1,44 @@
+//===-- copyprof_per_object_state.h ---------------------------*- C++ -*-===//
+//
+// 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 declares per-object state data structures and helper functions
+/// for tracking dynamic memory allocations associated with object copies.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef COPYPROF_PER_OBJECT_STATE_H
+#define COPYPROF_PER_OBJECT_STATE_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __copyprof {
+
+// Initializes the per-object state tracking.
+// Must be called once at program startup, after flags are initialized.
+void InitializePerObjectTracking();
+
+// Initializes the per-object state for the object at `this_ptr` with the given
+// static size.
+void InitPerObjectState(const void* this_ptr, uptr static_size);
+
+// Records a dynamic allocation of `num_bytes` for the object at `this_ptr`.
+void RecordPerObjectAllocation(const void* this_ptr, uptr num_bytes);
+
+// Returns the tracked size for the object at `this_ptr`.
+uptr GetPerObjectTrackedSize(const void* this_ptr);
+
+// Returns whether the object at `this_ptr` has performed any dynamic
+// allocations.
+bool GetPerObjectDidAllocate(const void* this_ptr);
+
+// Removes the per-object state for the object at `this_ptr`.
+void RemovePerObjectState(const void* this_ptr);
+
+} // namespace __copyprof
+
+#endif // COPYPROF_PER_OBJECT_STATE_H
diff --git a/compiler-rt/lib/copyprof/copyprof_reporting.cpp b/compiler-rt/lib/copyprof/copyprof_reporting.cpp
index 439438bc12c842..2a1d6162a8792e 100644
--- a/compiler-rt/lib/copyprof/copyprof_reporting.cpp
+++ b/compiler-rt/lib/copyprof/copyprof_reporting.cpp
@@ -13,7 +13,6 @@
#include "copyprof_reporting.h"
-#include "copyprof_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
@@ -39,4 +38,5 @@ void LogCopyProfReport(uptr pc, uptr bp, uptr obj_size, bool did_allocate) {
stack_trace.PrintTo(&output);
Printf("%s", output.data());
}
+
} // namespace __copyprof
diff --git a/compiler-rt/lib/copyprof/copyprof_reporting.h b/compiler-rt/lib/copyprof/copyprof_reporting.h
index 17b5be426346fd..a2aeb166abe433 100644
--- a/compiler-rt/lib/copyprof/copyprof_reporting.h
+++ b/compiler-rt/lib/copyprof/copyprof_reporting.h
@@ -19,8 +19,9 @@
namespace __copyprof {
// Prints a CopyProf report to stderr. `pc` and `bp` are the program counter
-// and frame pointer where the copy was destroyed, `obj_size` its flat size in
-// bytes, and `did_allocate` whether the copy allocated memory.
+// and frame pointer where the copy was destroyed, `obj_size` its size in bytes
+// (including memory allocated while copying it), and `did_allocate` whether
+// the copy allocated memory.
void LogCopyProfReport(uptr pc, uptr bp, uptr obj_size, bool did_allocate);
} // namespace __copyprof
diff --git a/compiler-rt/lib/copyprof/copyprof_state.cpp b/compiler-rt/lib/copyprof/copyprof_state.cpp
index 4da7b1f77ff1a8..83737d9fd9597f 100644
--- a/compiler-rt/lib/copyprof/copyprof_state.cpp
+++ b/compiler-rt/lib/copyprof/copyprof_state.cpp
@@ -17,4 +17,14 @@ namespace __copyprof {
THREADLOCAL PerThreadState __copyprof_state;
+void PerObjectState::SetStaticSize(usize num_bytes) {
+ tracked_size = num_bytes;
+}
+
+void PerObjectState::IncreaseTrackedSize(usize num_bytes) {
+ tracked_size += num_bytes;
+}
+
+usize PerObjectState::GetTrackedSize() const { return tracked_size; }
+
} // namespace __copyprof
diff --git a/compiler-rt/lib/copyprof/copyprof_state.h b/compiler-rt/lib/copyprof/copyprof_state.h
index e8b5f3bf2b0b4d..327af37ab93c6e 100644
--- a/compiler-rt/lib/copyprof/copyprof_state.h
+++ b/com...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/235455
More information about the llvm-branch-commits
mailing list