Recently, I came across following core dump from libasan
:
#0 0x00007fffe76c7387 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:55
#1 0x00007fffe76c8a78 in __GI_abort () at abort.c:90
#2 0x00007ffff74c4582 in __sanitizer::Abort() () from /usr/lib64/libasan.so.6
#3 0x00007ffff74d012c in __sanitizer::Die() () from /usr/lib64/libasan.so.6
#4 0x00007ffff74af63c in __asan::ScopedInErrorReport::~ScopedInErrorReport() () from /usr/lib64/libasan.so.6
#5 0x00007ffff74ad989 in __asan::ReportMallocUsableSizeNotOwned(unsigned long, __sanitizer::BufferedStackTrace*) () from /usr/lib64/libasan.so.6
#6 0x00007ffff7418b82 in __asan::asan_malloc_usable_size(void const*, unsigned long, unsigned long) () from /usr/lib64/libasan.so.6
......;
To debug this issue, I checked libasan source code and found there is a 16-byte
ChunkHeader in front of user memory which records the information of the used memory:
class ChunkHeader {
public:
atomic_uint8_t chunk_state;
u8 alloc_type : 2;
u8 lsan_tag : 2;
// align < 8 -> 0
// else -> log2(min(align, 512)) - 2
u8 user_requested_alignment_log : 3;
private:
u16 user_requested_size_hi;
u32 user_requested_size_lo;
atomic_uint64_t alloc_context_id;
......
}
By using user_requested_size_hi
and user_requested_size_lo
, we can calculate how much memory is required, and if it is 0
, the above exception will be reported:
uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
if (!ptr) return 0;
uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
if (flags()->check_malloc_usable_size && (usable_size == 0)) {
GET_STACK_TRACE_FATAL(pc, bp);
ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
}
return usable_size;
}