[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