[compiler-rt] [asan] API for getting multiple pointer ranges (PR #181446)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 13 19:07:18 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: Maksim Ivanov (emaxx-google)
<details>
<summary>Changes</summary>
Add an API that, unlike __asan_get_report_address(), can return multiple addresses and sizes. E.g., a handler might be interested in inspecting the source and the destination ranges of a memcpy-param-overlap error.
---
Full diff: https://github.com/llvm/llvm-project/pull/181446.diff
7 Files Affected:
- (modified) compiler-rt/include/sanitizer/asan_interface.h (+24)
- (modified) compiler-rt/lib/asan/asan_errors.h (+5-3)
- (modified) compiler-rt/lib/asan/asan_interceptors_memintrinsics.h (+25-25)
- (modified) compiler-rt/lib/asan/asan_interface.inc (+1)
- (modified) compiler-rt/lib/asan/asan_interface_internal.h (+12)
- (modified) compiler-rt/lib/asan/asan_report.cpp (+105-3)
- (modified) compiler-rt/lib/asan/asan_report.h (+2-2)
``````````diff
diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h
index 544f2e4b32687..5de4ea1ca5794 100644
--- a/compiler-rt/include/sanitizer/asan_interface.h
+++ b/compiler-rt/include/sanitizer/asan_interface.h
@@ -174,6 +174,30 @@ int SANITIZER_CDECL __asan_get_report_access_type(void);
/// \returns Access size in bytes.
size_t SANITIZER_CDECL __asan_get_report_access_size(void);
+typedef enum {
+ // Source address (e.g. memcpy source, or the address being read from).
+ __asan_address_info_src = 1,
+ // Destination address (e.g. memcpy dest, or the address being written to).
+ __asan_address_info_dest = 2,
+ // Address being deallocated (lifetime is terminated).
+ __asan_address_info_dealloc = 3,
+ // First non-dereferenced operand (e.g. pointer comparison, ODR definition).
+ __asan_address_info_first = 4,
+ // Second non-dereferenced operand (e.g. pointer comparison, ODR definition).
+ __asan_address_info_second = 5,
+} __asan_address_info_type;
+
+/// Gets a specific address or address range involved in the current error.
+///
+/// \param type __asan_address_info_type which the info is requested for.
+/// \param out_addr [out] Storage for the address.
+/// \param out_size [out] Storage for the range size. Zero may be reported
+/// (e.g., for pointer comparison errors as no dereferencing occurs).
+///
+/// \returns 1 if found, 0 otherwise.
+int SANITIZER_CDECL __asan_get_report_address_info(int type, void **out_addr,
+ size_t *out_size);
+
/// Gets the bug description of an ASan error (useful for calling from a
/// debugger).
///
diff --git a/compiler-rt/lib/asan/asan_errors.h b/compiler-rt/lib/asan/asan_errors.h
index f339b35d2a764..06ec69f0f4547 100644
--- a/compiler-rt/lib/asan/asan_errors.h
+++ b/compiler-rt/lib/asan/asan_errors.h
@@ -301,14 +301,16 @@ struct ErrorStringFunctionSizeOverflow : ErrorBase {
const BufferedStackTrace *stack;
AddressDescription addr_description;
uptr size;
+ bool is_write;
ErrorStringFunctionSizeOverflow() = default; // (*)
- ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_,
- uptr addr, uptr size_)
+ ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace* stack_,
+ uptr addr, uptr size_, bool is_write_)
: ErrorBase(tid, 10, "negative-size-param"),
stack(stack_),
addr_description(addr, /*shouldLockThreadRegistry=*/false),
- size(size_) {}
+ size(size_),
+ is_write(is_write_) {}
void Print();
};
diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h
index ec988cff51c59..f7759caf68e2c 100644
--- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h
+++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h
@@ -53,31 +53,31 @@ struct AsanInterceptorContext {
// that no extra frames are created, and stack trace contains
// relevant information only.
// We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) \
- do { \
- uptr __offset = (uptr)(offset); \
- uptr __size = (uptr)(size); \
- uptr __bad = 0; \
- if (UNLIKELY(__offset > __offset + __size)) { \
- GET_STACK_TRACE_FATAL_HERE; \
- ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
- } \
- if (UNLIKELY(!QuickCheckForUnpoisonedRegion(__offset, __size)) && \
- (__bad = __asan_region_is_poisoned(__offset, __size))) { \
- AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
- bool suppressed = false; \
- if (_ctx) { \
- suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
- if (!suppressed && HaveStackTraceBasedSuppressions()) { \
- GET_STACK_TRACE_FATAL_HERE; \
- suppressed = IsStackTraceSuppressed(&stack); \
- } \
- } \
- if (!suppressed) { \
- GET_CURRENT_PC_BP_SP; \
- ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false); \
- } \
- } \
+#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) \
+ do { \
+ uptr __offset = (uptr)(offset); \
+ uptr __size = (uptr)(size); \
+ uptr __bad = 0; \
+ if (UNLIKELY(__offset > __offset + __size)) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionSizeOverflow(__offset, __size, isWrite, &stack); \
+ } \
+ if (UNLIKELY(!QuickCheckForUnpoisonedRegion(__offset, __size)) && \
+ (__bad = __asan_region_is_poisoned(__offset, __size))) { \
+ AsanInterceptorContext* _ctx = (AsanInterceptorContext*)ctx; \
+ bool suppressed = false; \
+ if (_ctx) { \
+ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
+ if (!suppressed && HaveStackTraceBasedSuppressions()) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ suppressed = IsStackTraceSuppressed(&stack); \
+ } \
+ } \
+ if (!suppressed) { \
+ GET_CURRENT_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false); \
+ } \
+ } \
} while (0)
#define ASAN_READ_RANGE(ctx, offset, size) \
diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc
index b465356b1e443..7cbc4e636b5ab 100644
--- a/compiler-rt/lib/asan/asan_interface.inc
+++ b/compiler-rt/lib/asan/asan_interface.inc
@@ -33,6 +33,7 @@ INTERFACE_FUNCTION(__asan_get_free_stack)
INTERFACE_FUNCTION(__asan_get_report_access_size)
INTERFACE_FUNCTION(__asan_get_report_access_type)
INTERFACE_FUNCTION(__asan_get_report_address)
+INTERFACE_FUNCTION(__asan_get_report_address_info)
INTERFACE_FUNCTION(__asan_get_report_bp)
INTERFACE_FUNCTION(__asan_get_report_description)
INTERFACE_FUNCTION(__asan_get_report_pc)
diff --git a/compiler-rt/lib/asan/asan_interface_internal.h b/compiler-rt/lib/asan/asan_interface_internal.h
index a998263780221..ab09c5028f587 100644
--- a/compiler-rt/lib/asan/asan_interface_internal.h
+++ b/compiler-rt/lib/asan/asan_interface_internal.h
@@ -157,6 +157,18 @@ extern "C" {
int __asan_get_report_access_type();
SANITIZER_INTERFACE_ATTRIBUTE
uptr __asan_get_report_access_size();
+
+ typedef enum {
+ __asan_address_info_src = 1,
+ __asan_address_info_dest = 2,
+ __asan_address_info_dealloc = 3,
+ __asan_address_info_first = 4,
+ __asan_address_info_second = 5,
+ } __asan_address_info_type;
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __asan_get_report_address_info(int type, uptr* out_addr, uptr* out_size);
+
SANITIZER_INTERFACE_ATTRIBUTE
const char * __asan_get_report_description();
diff --git a/compiler-rt/lib/asan/asan_report.cpp b/compiler-rt/lib/asan/asan_report.cpp
index e049a21e4e16d..e19626934e272 100644
--- a/compiler-rt/lib/asan/asan_report.cpp
+++ b/compiler-rt/lib/asan/asan_report.cpp
@@ -366,11 +366,11 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function,
in_report.ReportError(error);
}
-void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
- BufferedStackTrace *stack) {
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size, bool is_write,
+ BufferedStackTrace* stack) {
ScopedInErrorReport in_report;
ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
- size);
+ size, is_write);
in_report.ReportError(error);
}
@@ -602,6 +602,108 @@ uptr __asan_get_report_access_size() {
return 0;
}
+int __asan_get_report_address_info(int type, uptr* out_addr, uptr* out_size) {
+ ErrorDescription& err = ScopedInErrorReport::CurrentError();
+ switch (type) {
+ case __asan_address_info_src:
+ if (err.kind == kErrorKindGeneric && !err.Generic.is_write) {
+ *out_addr = err.Generic.addr_description.Address();
+ *out_size = err.Generic.access_size;
+ return 1;
+ }
+ if (err.kind == kErrorKindStringFunctionMemoryRangesOverlap) {
+ *out_addr =
+ err.StringFunctionMemoryRangesOverlap.addr2_description.Address();
+ *out_size = err.StringFunctionMemoryRangesOverlap.length2;
+ return 1;
+ }
+ if (err.kind == kErrorKindStringFunctionSizeOverflow &&
+ !err.StringFunctionSizeOverflow.is_write) {
+ *out_addr = err.StringFunctionSizeOverflow.addr_description.Address();
+ *out_size = err.StringFunctionSizeOverflow.size;
+ return 1;
+ }
+ if (err.kind == kErrorKindMallocUsableSizeNotOwned) {
+ *out_addr = err.MallocUsableSizeNotOwned.addr_description.Address();
+ *out_size = 0;
+ return 1;
+ }
+ if (err.kind == kErrorKindSanitizerGetAllocatedSizeNotOwned) {
+ *out_addr =
+ err.SanitizerGetAllocatedSizeNotOwned.addr_description.Address();
+ *out_size = 0;
+ return 1;
+ }
+ break;
+ case __asan_address_info_dest:
+ if (err.kind == kErrorKindGeneric && err.Generic.is_write) {
+ *out_addr = err.Generic.addr_description.Address();
+ *out_size = err.Generic.access_size;
+ return 1;
+ }
+ if (err.kind == kErrorKindStringFunctionMemoryRangesOverlap) {
+ *out_addr =
+ err.StringFunctionMemoryRangesOverlap.addr1_description.Address();
+ *out_size = err.StringFunctionMemoryRangesOverlap.length1;
+ return 1;
+ }
+ if (err.kind == kErrorKindStringFunctionSizeOverflow &&
+ err.StringFunctionSizeOverflow.is_write) {
+ *out_addr = err.StringFunctionSizeOverflow.addr_description.Address();
+ *out_size = err.StringFunctionSizeOverflow.size;
+ return 1;
+ }
+ break;
+ case __asan_address_info_dealloc:
+ if (err.kind == kErrorKindDoubleFree) {
+ *out_addr = err.DoubleFree.addr_description.addr;
+ *out_size = 0;
+ return 1;
+ }
+ if (err.kind == kErrorKindNewDeleteTypeMismatch) {
+ *out_addr = err.NewDeleteTypeMismatch.addr_description.addr;
+ *out_size = err.NewDeleteTypeMismatch.delete_size;
+ return 1;
+ }
+ if (err.kind == kErrorKindFreeNotMalloced) {
+ *out_addr = err.FreeNotMalloced.addr_description.Address();
+ *out_size = 0;
+ return 1;
+ }
+ if (err.kind == kErrorKindAllocTypeMismatch) {
+ *out_addr = err.AllocTypeMismatch.addr_description.Address();
+ *out_size = 0;
+ return 1;
+ }
+ break;
+ case __asan_address_info_first:
+ if (err.kind == kErrorKindInvalidPointerPair) {
+ *out_addr = err.InvalidPointerPair.addr1_description.Address();
+ *out_size = 0;
+ return 1;
+ }
+ if (err.kind == kErrorKindODRViolation) {
+ *out_addr = err.ODRViolation.global1.beg;
+ *out_size = 0;
+ return 1;
+ }
+ break;
+ case __asan_address_info_second:
+ if (err.kind == kErrorKindInvalidPointerPair) {
+ *out_addr = err.InvalidPointerPair.addr2_description.Address();
+ *out_size = 0;
+ return 1;
+ }
+ if (err.kind == kErrorKindODRViolation) {
+ *out_addr = err.ODRViolation.global2.beg;
+ *out_size = 0;
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
const char *__asan_get_report_description() {
if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
return ScopedInErrorReport::CurrentError().Generic.bug_descr;
diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h
index 3143d83abe390..b6c2b3eae7c70 100644
--- a/compiler-rt/lib/asan/asan_report.h
+++ b/compiler-rt/lib/asan/asan_report.h
@@ -79,8 +79,8 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function,
const char *offset1, uptr length1,
const char *offset2, uptr length2,
BufferedStackTrace *stack);
-void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
- BufferedStackTrace *stack);
+void ReportStringFunctionSizeOverflow(uptr offset, uptr size, bool is_write,
+ BufferedStackTrace* stack);
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
uptr old_mid, uptr new_mid,
BufferedStackTrace *stack);
``````````
</details>
https://github.com/llvm/llvm-project/pull/181446
More information about the llvm-commits
mailing list