[asan] API for getting multiple pointer ranges (#181446)
Add an API that, unlike __asan_get_report_address(), can return multiple addresses and sizes. This allows a handler to inspect the source and the destination ranges of errors that have more than one pointer involved (e.g., memcpy-param-overlap). Fixes #155406. Assisted-by: Gemini --------- Co-authored-by: Vitaly Buka <vitalybuka@google.com>
This commit is contained in:
@@ -174,6 +174,56 @@ int SANITIZER_CDECL __asan_get_report_access_type(void);
|
|||||||
/// \returns Access size in bytes.
|
/// \returns Access size in bytes.
|
||||||
size_t SANITIZER_CDECL __asan_get_report_access_size(void);
|
size_t SANITIZER_CDECL __asan_get_report_access_size(void);
|
||||||
|
|
||||||
|
/// Gets the source address or address range involved in the current error
|
||||||
|
/// (e.g., memcpy source, or the address being read from).
|
||||||
|
///
|
||||||
|
/// \param out_addr [out] Storage for the address.
|
||||||
|
/// \param out_size [out] Storage for the range size.
|
||||||
|
///
|
||||||
|
/// \returns 1 if found, 0 otherwise.
|
||||||
|
int SANITIZER_CDECL __asan_get_report_src_address(const void **out_addr,
|
||||||
|
size_t *out_size);
|
||||||
|
|
||||||
|
/// Gets the destination address or address range involved in the current error
|
||||||
|
/// (e.g., memcpy dest, or the address being written to).
|
||||||
|
///
|
||||||
|
/// \param out_addr [out] Storage for the address.
|
||||||
|
/// \param out_size [out] Storage for the range size.
|
||||||
|
///
|
||||||
|
/// \returns 1 if found, 0 otherwise.
|
||||||
|
int SANITIZER_CDECL __asan_get_report_dest_address(const void **out_addr,
|
||||||
|
size_t *out_size);
|
||||||
|
|
||||||
|
/// Gets the address or address range being deallocated in the current error
|
||||||
|
/// (lifetime is terminated).
|
||||||
|
///
|
||||||
|
/// \param out_addr [out] Storage for the address.
|
||||||
|
/// \param out_size [out] Storage for the range size.
|
||||||
|
///
|
||||||
|
/// \returns 1 if found, 0 otherwise.
|
||||||
|
int SANITIZER_CDECL __asan_get_report_dealloc_address(const void **out_addr,
|
||||||
|
size_t *out_size);
|
||||||
|
|
||||||
|
/// Gets the first non-dereferenced operand address involved in the current
|
||||||
|
/// error (e.g., pointer comparison or ODR violation).
|
||||||
|
///
|
||||||
|
/// \param out_addr [out] Storage for the address.
|
||||||
|
/// \param out_size [out] Storage for the range size. Zero may be reported.
|
||||||
|
///
|
||||||
|
/// \returns 1 if found, 0 otherwise.
|
||||||
|
int SANITIZER_CDECL __asan_get_report_first_address(const void **out_addr,
|
||||||
|
size_t *out_size);
|
||||||
|
|
||||||
|
/// Gets the second non-dereferenced operand address involved in the current
|
||||||
|
/// error (e.g., pointer comparison or ODR violation).
|
||||||
|
///
|
||||||
|
/// \param out_addr [out] Storage for the address.
|
||||||
|
/// \param out_size [out] Storage for the range size. Zero may be reported.
|
||||||
|
///
|
||||||
|
/// \returns 1 if found, 0 otherwise.
|
||||||
|
int SANITIZER_CDECL __asan_get_report_second_address(const void **out_addr,
|
||||||
|
size_t *out_size);
|
||||||
|
|
||||||
/// Gets the bug description of an ASan error (useful for calling from a
|
/// Gets the bug description of an ASan error (useful for calling from a
|
||||||
/// debugger).
|
/// debugger).
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -298,16 +298,16 @@ struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase {
|
|||||||
const char *function;
|
const char *function;
|
||||||
|
|
||||||
ErrorStringFunctionMemoryRangesOverlap() = default; // (*)
|
ErrorStringFunctionMemoryRangesOverlap() = default; // (*)
|
||||||
ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_,
|
ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace* stack,
|
||||||
uptr addr1, uptr length1_, uptr addr2,
|
uptr addr1, uptr length1, uptr addr2,
|
||||||
uptr length2_, const char *function_)
|
uptr length2, const char* function)
|
||||||
: ErrorBase(tid),
|
: ErrorBase(tid),
|
||||||
stack(stack_),
|
stack(stack),
|
||||||
length1(length1_),
|
length1(length1),
|
||||||
length2(length2_),
|
length2(length2),
|
||||||
addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false),
|
addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false),
|
||||||
addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false),
|
addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false),
|
||||||
function(function_) {
|
function(function) {
|
||||||
char bug_type[100];
|
char bug_type[100];
|
||||||
internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
|
internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
|
||||||
scariness.Clear();
|
scariness.Clear();
|
||||||
@@ -320,14 +320,16 @@ struct ErrorStringFunctionSizeOverflow : ErrorBase {
|
|||||||
const BufferedStackTrace *stack;
|
const BufferedStackTrace *stack;
|
||||||
AddressDescription addr_description;
|
AddressDescription addr_description;
|
||||||
uptr size;
|
uptr size;
|
||||||
|
bool is_write;
|
||||||
|
|
||||||
ErrorStringFunctionSizeOverflow() = default; // (*)
|
ErrorStringFunctionSizeOverflow() = default; // (*)
|
||||||
ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_,
|
ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace* stack, uptr addr,
|
||||||
uptr addr, uptr size_)
|
uptr size, bool is_write)
|
||||||
: ErrorBase(tid, 10, "negative-size-param"),
|
: ErrorBase(tid, 10, "negative-size-param"),
|
||||||
stack(stack_),
|
stack(stack),
|
||||||
addr_description(addr, /*shouldLockThreadRegistry=*/false),
|
addr_description(addr, /*shouldLockThreadRegistry=*/false),
|
||||||
size(size_) {}
|
size(size),
|
||||||
|
is_write(is_write) {}
|
||||||
void Print();
|
void Print();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -53,31 +53,31 @@ struct AsanInterceptorContext {
|
|||||||
// that no extra frames are created, and stack trace contains
|
// that no extra frames are created, and stack trace contains
|
||||||
// relevant information only.
|
// relevant information only.
|
||||||
// We check all shadow bytes.
|
// We check all shadow bytes.
|
||||||
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) \
|
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) \
|
||||||
do { \
|
do { \
|
||||||
uptr __offset = (uptr)(offset); \
|
uptr __offset = (uptr)(offset); \
|
||||||
uptr __size = (uptr)(size); \
|
uptr __size = (uptr)(size); \
|
||||||
uptr __bad = 0; \
|
uptr __bad = 0; \
|
||||||
if (UNLIKELY(__offset > __offset + __size)) { \
|
if (UNLIKELY(__offset > __offset + __size)) { \
|
||||||
GET_STACK_TRACE_FATAL_HERE; \
|
GET_STACK_TRACE_FATAL_HERE; \
|
||||||
ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
|
ReportStringFunctionSizeOverflow(__offset, __size, isWrite, &stack); \
|
||||||
} \
|
} \
|
||||||
if (UNLIKELY(!QuickCheckForUnpoisonedRegion(__offset, __size)) && \
|
if (UNLIKELY(!QuickCheckForUnpoisonedRegion(__offset, __size)) && \
|
||||||
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
|
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
|
||||||
AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
|
AsanInterceptorContext* _ctx = (AsanInterceptorContext*)ctx; \
|
||||||
bool suppressed = false; \
|
bool suppressed = false; \
|
||||||
if (_ctx) { \
|
if (_ctx) { \
|
||||||
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
|
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
|
||||||
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
|
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
|
||||||
GET_STACK_TRACE_FATAL_HERE; \
|
GET_STACK_TRACE_FATAL_HERE; \
|
||||||
suppressed = IsStackTraceSuppressed(&stack); \
|
suppressed = IsStackTraceSuppressed(&stack); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
if (!suppressed) { \
|
if (!suppressed) { \
|
||||||
GET_CURRENT_PC_BP_SP; \
|
GET_CURRENT_PC_BP_SP; \
|
||||||
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false); \
|
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ASAN_READ_RANGE(ctx, offset, size) \
|
#define ASAN_READ_RANGE(ctx, offset, size) \
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ INTERFACE_FUNCTION(__asan_get_free_stack)
|
|||||||
INTERFACE_FUNCTION(__asan_get_report_access_size)
|
INTERFACE_FUNCTION(__asan_get_report_access_size)
|
||||||
INTERFACE_FUNCTION(__asan_get_report_access_type)
|
INTERFACE_FUNCTION(__asan_get_report_access_type)
|
||||||
INTERFACE_FUNCTION(__asan_get_report_address)
|
INTERFACE_FUNCTION(__asan_get_report_address)
|
||||||
|
INTERFACE_FUNCTION(__asan_get_report_src_address)
|
||||||
|
INTERFACE_FUNCTION(__asan_get_report_dest_address)
|
||||||
|
INTERFACE_FUNCTION(__asan_get_report_dealloc_address)
|
||||||
|
INTERFACE_FUNCTION(__asan_get_report_first_address)
|
||||||
|
INTERFACE_FUNCTION(__asan_get_report_second_address)
|
||||||
INTERFACE_FUNCTION(__asan_get_report_bp)
|
INTERFACE_FUNCTION(__asan_get_report_bp)
|
||||||
INTERFACE_FUNCTION(__asan_get_report_description)
|
INTERFACE_FUNCTION(__asan_get_report_description)
|
||||||
INTERFACE_FUNCTION(__asan_get_report_pc)
|
INTERFACE_FUNCTION(__asan_get_report_pc)
|
||||||
|
|||||||
@@ -157,6 +157,18 @@ extern "C" {
|
|||||||
int __asan_get_report_access_type();
|
int __asan_get_report_access_type();
|
||||||
SANITIZER_INTERFACE_ATTRIBUTE
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
uptr __asan_get_report_access_size();
|
uptr __asan_get_report_access_size();
|
||||||
|
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
int __asan_get_report_src_address(uptr* out_addr, uptr* out_size);
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
int __asan_get_report_dest_address(uptr* out_addr, uptr* out_size);
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
int __asan_get_report_dealloc_address(uptr* out_addr, uptr* out_size);
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
int __asan_get_report_first_address(uptr* out_addr, uptr* out_size);
|
||||||
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
|
int __asan_get_report_second_address(uptr* out_addr, uptr* out_size);
|
||||||
|
|
||||||
SANITIZER_INTERFACE_ATTRIBUTE
|
SANITIZER_INTERFACE_ATTRIBUTE
|
||||||
const char * __asan_get_report_description();
|
const char * __asan_get_report_description();
|
||||||
|
|
||||||
|
|||||||
@@ -374,11 +374,11 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
|||||||
in_report.ReportError(error);
|
in_report.ReportError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
void ReportStringFunctionSizeOverflow(uptr offset, uptr size, bool is_write,
|
||||||
BufferedStackTrace *stack) {
|
BufferedStackTrace* stack) {
|
||||||
ScopedInErrorReport in_report;
|
ScopedInErrorReport in_report;
|
||||||
ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
|
ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
|
||||||
size);
|
size, is_write);
|
||||||
in_report.ReportError(error);
|
in_report.ReportError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,6 +610,148 @@ uptr __asan_get_report_access_size() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __asan_get_report_src_address(uptr* out_addr, uptr* out_size) {
|
||||||
|
ErrorDescription& err = ScopedInErrorReport::CurrentError();
|
||||||
|
if (err.kind == kErrorKindGeneric && !err.Generic.is_write) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.Generic.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.Generic.access_size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindStringFunctionMemoryRangesOverlap) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr =
|
||||||
|
err.StringFunctionMemoryRangesOverlap.addr2_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.StringFunctionMemoryRangesOverlap.length2;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindStringFunctionSizeOverflow &&
|
||||||
|
!err.StringFunctionSizeOverflow.is_write) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.StringFunctionSizeOverflow.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.StringFunctionSizeOverflow.size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindMallocUsableSizeNotOwned) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.MallocUsableSizeNotOwned.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindSanitizerGetAllocatedSizeNotOwned) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr =
|
||||||
|
err.SanitizerGetAllocatedSizeNotOwned.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __asan_get_report_dest_address(uptr* out_addr, uptr* out_size) {
|
||||||
|
ErrorDescription& err = ScopedInErrorReport::CurrentError();
|
||||||
|
if (err.kind == kErrorKindGeneric && err.Generic.is_write) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.Generic.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.Generic.access_size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindStringFunctionMemoryRangesOverlap) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr =
|
||||||
|
err.StringFunctionMemoryRangesOverlap.addr1_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.StringFunctionMemoryRangesOverlap.length1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindStringFunctionSizeOverflow &&
|
||||||
|
err.StringFunctionSizeOverflow.is_write) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.StringFunctionSizeOverflow.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.StringFunctionSizeOverflow.size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __asan_get_report_dealloc_address(uptr* out_addr, uptr* out_size) {
|
||||||
|
ErrorDescription& err = ScopedInErrorReport::CurrentError();
|
||||||
|
if (err.kind == kErrorKindDoubleFree) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.DoubleFree.addr_description.addr;
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindNewDeleteTypeMismatch) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.NewDeleteTypeMismatch.addr_description.addr;
|
||||||
|
if (out_size)
|
||||||
|
*out_size = err.NewDeleteTypeMismatch.delete_size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindFreeNotMalloced) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.FreeNotMalloced.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindAllocTypeMismatch) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.AllocTypeMismatch.addr_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __asan_get_report_first_address(uptr* out_addr, uptr* out_size) {
|
||||||
|
ErrorDescription& err = ScopedInErrorReport::CurrentError();
|
||||||
|
if (err.kind == kErrorKindInvalidPointerPair) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.InvalidPointerPair.addr1_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindODRViolation) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.ODRViolation.global1.beg;
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __asan_get_report_second_address(uptr* out_addr, uptr* out_size) {
|
||||||
|
ErrorDescription& err = ScopedInErrorReport::CurrentError();
|
||||||
|
if (err.kind == kErrorKindInvalidPointerPair) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.InvalidPointerPair.addr2_description.Address();
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err.kind == kErrorKindODRViolation) {
|
||||||
|
if (out_addr)
|
||||||
|
*out_addr = err.ODRViolation.global2.beg;
|
||||||
|
if (out_size)
|
||||||
|
*out_size = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *__asan_get_report_description() {
|
const char *__asan_get_report_description() {
|
||||||
if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
|
if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
|
||||||
return ScopedInErrorReport::CurrentError().Generic.bug_descr;
|
return ScopedInErrorReport::CurrentError().Generic.bug_descr;
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
|||||||
const char *offset1, uptr length1,
|
const char *offset1, uptr length1,
|
||||||
const char *offset2, uptr length2,
|
const char *offset2, uptr length2,
|
||||||
BufferedStackTrace *stack);
|
BufferedStackTrace *stack);
|
||||||
void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
void ReportStringFunctionSizeOverflow(uptr offset, uptr size, bool is_write,
|
||||||
BufferedStackTrace *stack);
|
BufferedStackTrace* stack);
|
||||||
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
|
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
|
||||||
uptr old_mid, uptr new_mid,
|
uptr old_mid, uptr new_mid,
|
||||||
BufferedStackTrace *stack);
|
BufferedStackTrace *stack);
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ __asan_on_error() {
|
|||||||
// CHECK: addr: {{0x0*}}[[ADDR]]
|
// CHECK: addr: {{0x0*}}[[ADDR]]
|
||||||
fprintf(stderr, "description: %s\n", description);
|
fprintf(stderr, "description: %s\n", description);
|
||||||
// CHECK: description: double-free
|
// CHECK: description: double-free
|
||||||
|
|
||||||
|
const void *addr_dealloc = NULL;
|
||||||
|
size_t size_dealloc = 0xbad;
|
||||||
|
int is_dealloc =
|
||||||
|
__asan_get_report_dealloc_address(&addr_dealloc, &size_dealloc);
|
||||||
|
fprintf(stderr,
|
||||||
|
"is_dealloc: %d, addr_dealloc: " PTR_FMT ", size_dealloc: %zu\n",
|
||||||
|
is_dealloc, addr_dealloc, size_dealloc);
|
||||||
|
// CHECK: is_dealloc: 1, addr_dealloc: 0x[[ADDR]], size_dealloc: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: AddressSanitizer: attempting double-free on {{0x0*}}[[ADDR]] in thread T0
|
// CHECK: AddressSanitizer: attempting double-free on {{0x0*}}[[ADDR]] in thread T0
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// Checks that the ASan debugging API for getting report information
|
||||||
|
// returns correct values for invalid pointer pairs.
|
||||||
|
// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-detect-invalid-pointer-pair && %env_asan_opts=detect_invalid_pointer_pairs=1 not %run %t 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// If we use %p with MS CRTs, it comes out all upper case. Use %08x to get
|
||||||
|
// lowercase hex.
|
||||||
|
#ifdef _WIN32
|
||||||
|
# ifdef _WIN64
|
||||||
|
# define PTR_FMT "0x%08llx"
|
||||||
|
# else
|
||||||
|
# define PTR_FMT "0x%08x"
|
||||||
|
# endif
|
||||||
|
// Solaris libc omits the leading 0x.
|
||||||
|
#elif defined(__sun__) && defined(__svr4__)
|
||||||
|
# define PTR_FMT "0x%p"
|
||||||
|
#else
|
||||||
|
# define PTR_FMT "%p"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *p;
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Disable stderr buffering. Needed on Windows.
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
p = (char *)malloc(42);
|
||||||
|
q = (char *)malloc(42);
|
||||||
|
|
||||||
|
fprintf(stderr, "p: " PTR_FMT "\n", p);
|
||||||
|
// CHECK: p: 0x[[ADDR1:[0-9a-f]+]]
|
||||||
|
fprintf(stderr, "q: " PTR_FMT "\n", q);
|
||||||
|
// CHECK: q: 0x[[ADDR2:[0-9a-f]+]]
|
||||||
|
|
||||||
|
// Trigger invalid pointer pair
|
||||||
|
int res = p > q; // BOOM
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
free(q);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for dyld macOS 12.0+
|
||||||
|
#if (__APPLE__)
|
||||||
|
__attribute__((weak))
|
||||||
|
#endif
|
||||||
|
extern "C" void __asan_on_error() {
|
||||||
|
int present = __asan_report_present();
|
||||||
|
fprintf(stderr, "%s\n", (present == 1) ? "report" : "");
|
||||||
|
// CHECK: report
|
||||||
|
|
||||||
|
const void *addr_first = NULL;
|
||||||
|
size_t size_first = 0xbad;
|
||||||
|
int is_first = __asan_get_report_first_address(&addr_first, &size_first);
|
||||||
|
fprintf(stderr, "is_first: %d, addr_first: " PTR_FMT ", size_first: %zu\n",
|
||||||
|
is_first, addr_first, size_first);
|
||||||
|
// CHECK: is_first: 1, addr_first: 0x[[ADDR1]], size_first: 0
|
||||||
|
|
||||||
|
const void *addr_second = NULL;
|
||||||
|
size_t size_second = 0xbad;
|
||||||
|
int is_second = __asan_get_report_second_address(&addr_second, &size_second);
|
||||||
|
fprintf(stderr, "is_second: %d, addr_second: " PTR_FMT ", size_second: %zu\n",
|
||||||
|
is_second, addr_second, size_second);
|
||||||
|
// CHECK: is_second: 1, addr_second: 0x[[ADDR2]], size_second: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: ERROR: AddressSanitizer: invalid-pointer-pair
|
||||||
59
compiler-rt/test/asan/TestCases/debug_memcpy_overlap.cpp
Normal file
59
compiler-rt/test/asan/TestCases/debug_memcpy_overlap.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Checks that the ASan debugging API for getting report information reports
|
||||||
|
// memory overlap error details.
|
||||||
|
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char buffer[10] = "hello";
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Disable stderr buffering. Needed on Windows.
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
// Trigger memcpy-param-overlap
|
||||||
|
memcpy(buffer, buffer + 1, 3); // BOOM
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we use %p with MS CRTs, it comes out all upper case. Use %08x to get
|
||||||
|
// lowercase hex.
|
||||||
|
#ifdef _WIN32
|
||||||
|
# ifdef _WIN64
|
||||||
|
# define PTR_FMT "0x%08llx"
|
||||||
|
# else
|
||||||
|
# define PTR_FMT "0x%08x"
|
||||||
|
# endif
|
||||||
|
// Solaris libc omits the leading 0x.
|
||||||
|
#elif defined(__sun__) && defined(__svr4__)
|
||||||
|
# define PTR_FMT "0x%p"
|
||||||
|
#else
|
||||||
|
# define PTR_FMT "%p"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Required for dyld macOS 12.0+
|
||||||
|
#if (__APPLE__)
|
||||||
|
__attribute__((weak))
|
||||||
|
#endif
|
||||||
|
extern "C" void __asan_on_error() {
|
||||||
|
int present = __asan_report_present();
|
||||||
|
fprintf(stderr, "%s\n", (present == 1) ? "report" : "");
|
||||||
|
// CHECK: report
|
||||||
|
|
||||||
|
const void *addr_src = NULL;
|
||||||
|
size_t size_src = 0;
|
||||||
|
int is_src = __asan_get_report_src_address(&addr_src, &size_src);
|
||||||
|
fprintf(stderr, "is_src: %d, addr_src: " PTR_FMT ", size_src: %zu\n", is_src,
|
||||||
|
addr_src, size_src);
|
||||||
|
// CHECK: is_src: 1, addr_src: 0x{{[0-9a-f]+}}, size_src: 3
|
||||||
|
|
||||||
|
const void *addr_dest = NULL;
|
||||||
|
size_t size_dest = 0;
|
||||||
|
int is_dest = __asan_get_report_dest_address(&addr_dest, &size_dest);
|
||||||
|
fprintf(stderr, "is_dest: %d, addr_dest: " PTR_FMT ", size_dest: %zu\n",
|
||||||
|
is_dest, addr_dest, size_dest);
|
||||||
|
// CHECK: is_dest: 1, addr_dest: 0x{{[0-9a-f]+}}, size_dest: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: memcpy-param-overlap
|
||||||
60
compiler-rt/test/asan/TestCases/debug_negative_size.cpp
Normal file
60
compiler-rt/test/asan/TestCases/debug_negative_size.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// Checks that the ASan debugging API for getting report information
|
||||||
|
// returns correct values for negative size parameter errors.
|
||||||
|
// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char buffer[10] = "hello";
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Disable stderr buffering. Needed on Windows.
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
// Trigger negative-size-param
|
||||||
|
memset(buffer, 0, (size_t)-1); // BOOM
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we use %p with MS CRTs, it comes out all upper case. Use %08x to get
|
||||||
|
// lowercase hex.
|
||||||
|
#ifdef _WIN32
|
||||||
|
# ifdef _WIN64
|
||||||
|
# define PTR_FMT "0x%08llx"
|
||||||
|
# else
|
||||||
|
# define PTR_FMT "0x%08x"
|
||||||
|
# endif
|
||||||
|
// Solaris libc omits the leading 0x.
|
||||||
|
#elif defined(__sun__) && defined(__svr4__)
|
||||||
|
# define PTR_FMT "0x%p"
|
||||||
|
#else
|
||||||
|
# define PTR_FMT "%p"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Required for dyld macOS 12.0+
|
||||||
|
#if (__APPLE__)
|
||||||
|
__attribute__((weak))
|
||||||
|
#endif
|
||||||
|
extern "C" void __asan_on_error() {
|
||||||
|
int present = __asan_report_present();
|
||||||
|
fprintf(stderr, "%s\n", (present == 1) ? "report" : "");
|
||||||
|
// CHECK: report
|
||||||
|
|
||||||
|
const void *addr_src = NULL;
|
||||||
|
size_t size_src = 0;
|
||||||
|
int is_src = __asan_get_report_src_address(&addr_src, &size_src);
|
||||||
|
fprintf(stderr, "is_src: %d\n", is_src);
|
||||||
|
// CHECK: is_src: 0
|
||||||
|
|
||||||
|
const void *addr_dest = NULL;
|
||||||
|
size_t size_dest = 0;
|
||||||
|
int is_dest = __asan_get_report_dest_address(&addr_dest, &size_dest);
|
||||||
|
// We check size_dest + 1 because size_dest is -1 (as size_t), which varies
|
||||||
|
// depending on the platform's size_t. Adding 1 should result in 0.
|
||||||
|
fprintf(stderr, "is_dest: %d, addr_dest: " PTR_FMT ", size_dest+1: %zu\n",
|
||||||
|
is_dest, addr_dest, size_dest + 1);
|
||||||
|
// CHECK: is_dest: 1, addr_dest: 0x{{[0-9a-f]+}}, size_dest+1: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: AddressSanitizer: negative-size-param
|
||||||
@@ -61,10 +61,21 @@ __asan_on_error() {
|
|||||||
// CHECK: addr: 0x[[ADDR:[0-9a-f]+]]
|
// CHECK: addr: 0x[[ADDR:[0-9a-f]+]]
|
||||||
fprintf(stderr, "type: %s\n", (is_write ? "write" : "read"));
|
fprintf(stderr, "type: %s\n", (is_write ? "write" : "read"));
|
||||||
// CHECK: type: write
|
// CHECK: type: write
|
||||||
fprintf(stderr, "access_size: %ld\n", access_size);
|
fprintf(stderr, "access_size: %zu\n", access_size);
|
||||||
// CHECK: access_size: 1
|
// CHECK: access_size: 1
|
||||||
fprintf(stderr, "description: %s\n", description);
|
fprintf(stderr, "description: %s\n", description);
|
||||||
// CHECK: description: heap-use-after-free
|
// CHECK: description: heap-use-after-free
|
||||||
|
|
||||||
|
const void *addr2 = NULL;
|
||||||
|
size_t size2 = 0;
|
||||||
|
int is_dest = __asan_get_report_dest_address(&addr2, &size2);
|
||||||
|
fprintf(stderr, "is_dest: %d, addr2: " PTR_FMT ", size2: %zu\n", is_dest,
|
||||||
|
addr2, size2);
|
||||||
|
// CHECK: is_dest: 1, addr2: 0x[[ADDR]], size2: 1
|
||||||
|
|
||||||
|
int is_src = __asan_get_report_src_address(&addr2, &size2);
|
||||||
|
fprintf(stderr, "is_src: %d\n", is_src);
|
||||||
|
// CHECK: is_src: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: AddressSanitizer: heap-use-after-free on address {{0x0*}}[[ADDR]] at pc {{0x0*}}[[PC]] bp {{0x0*}}[[BP]] sp {{0x0*}}[[SP]]
|
// CHECK: AddressSanitizer: heap-use-after-free on address {{0x0*}}[[ADDR]] at pc {{0x0*}}[[PC]] bp {{0x0*}}[[BP]] sp {{0x0*}}[[SP]]
|
||||||
|
|||||||
Reference in New Issue
Block a user