Index: lib/asan/asan_allocator.cc =================================================================== --- lib/asan/asan_allocator.cc +++ lib/asan/asan_allocator.cc @@ -523,6 +523,18 @@ AsanThread *t = GetCurrentThread(); m->free_tid = t ? t->tid() : 0; m->free_context_id = StackDepotPut(*stack); + + Flags &fl = *flags(); + if (fl.scribble) { + // We have to skip the chunk header, it contains free_context_id. + uptr scribble_start_ptr = (uptr)m + kChunkHeaderSize + kChunkHeader2Size; + if (m->UsedSize() >= kChunkHeader2Size) { // Skip Header2 in user area. + uptr size_to_scribble = m->UsedSize() - kChunkHeader2Size; + size_to_scribble = Min(size_to_scribble, (uptr)fl.max_malloc_fill_size); + REAL(memset)((void *)scribble_start_ptr, 0x55, size_to_scribble); + } + } + // Poison the region. PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), Index: lib/asan/asan_flags.inc =================================================================== --- lib/asan/asan_flags.inc +++ lib/asan/asan_flags.inc @@ -143,6 +143,8 @@ "If true, dump values of CPU registers when SEGV happens. Only " "available on OS X for now.") ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.") +ASAN_FLAG(bool, scribble, false, + "On free(), set each byte of released memory to 0x55.") ASAN_FLAG(bool, halt_on_error, true, "Crash the program after printing the first error report " "(WARNING: USE AT YOUR OWN RISK!)") Index: test/asan/TestCases/scribble.cc =================================================================== --- test/asan/TestCases/scribble.cc +++ test/asan/TestCases/scribble.cc @@ -0,0 +1,56 @@ +// RUN: %clang_asan -O2 %s -o %t +// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s +// RUN: %env_asan_opts=scribble=0 %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s +// RUN: %env_asan_opts=scribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s + +#include +#include +#include + +struct Isa { + const char *class_name; +}; + +struct MyClass { + long padding; + Isa *isa; + long data; + + void print_my_class_name(); +}; + +__attribute__((no_sanitize("address"))) +void MyClass::print_my_class_name() { + fprintf(stderr, "this = %p\n", this); + fprintf(stderr, "padding = 0x%lx\n", this->padding); + fprintf(stderr, "isa = %p\n", this->isa); + + if ((uint32_t)this->isa != 0x55555555) { + fprintf(stderr, "class name: %s\n", this->isa->class_name); + } +} + +int main() { + Isa *my_class_isa = (Isa *)malloc(sizeof(Isa)); + memset(my_class_isa, 0x77, sizeof(Isa)); + my_class_isa->class_name = "MyClass"; + + MyClass *my_object = (MyClass *)malloc(sizeof(MyClass)); + memset(my_object, 0x88, sizeof(MyClass)); + my_object->isa = my_class_isa; + my_object->data = 42; + + my_object->print_my_class_name(); + // CHECK-SCRIBBLE: class name: MyClass + // CHECK-NOSCRIBBLE: class name: MyClass + + free(my_object); + + my_object->print_my_class_name(); + // CHECK-NOSCRIBBLE: class name: MyClass + // CHECK-SCRIBBLE: isa = {{0x5555555555555555|0x55555555}} + + printf("okthxbai!\n"); + // CHECK-SCRIBBLE: okthxbai! + // CHECK-NOSCRIBBLE: okthxbai! +}