| 1 | // RUN: %clang_asan -O2 %s -o %t |
| 2 | // RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s |
| 3 | // RUN: %env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s |
| 4 | // RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s |
| 5 | |
| 6 | #include <stdint.h> |
| 7 | #include <stdio.h> |
| 8 | #include <stdlib.h> |
| 9 | #include <string.h> |
| 10 | |
| 11 | struct Isa { |
| 12 | const char *class_name; |
| 13 | }; |
| 14 | |
| 15 | struct MyClass { |
| 16 | // User memory and `ChunkHeader` overlap. In particular the `free_context_id` |
| 17 | // is stored at the beginning of user memory when it is freed. That part of |
| 18 | // user memory is not scribbled and is changed when the memory is freed. This |
| 19 | // test relies on `isa` being scribbled or unmodified after memory is freed. |
| 20 | // In order for this to work the start of `isa` must come after whatever is in |
| 21 | // `ChunkHeader` (currently the 64-bit `free_context_id`). The padding here is |
| 22 | // to ensure this is the case. |
| 23 | uint64_t padding; |
| 24 | Isa *isa; |
| 25 | long data; |
| 26 | |
| 27 | void print_my_class_name(); |
| 28 | }; |
| 29 | |
| 30 | __attribute__((no_sanitize("address" ))) |
| 31 | void MyClass::print_my_class_name() { |
| 32 | fprintf(stderr, format: "this = %p\n" , this); |
| 33 | fprintf(stderr, format: "padding = 0x%lx\n" , this->padding); |
| 34 | fprintf(stderr, format: "isa = %p\n" , this->isa); |
| 35 | |
| 36 | if ((uint32_t)(uintptr_t)this->isa != 0x55555555) { |
| 37 | fprintf(stderr, format: "class name: %s\n" , this->isa->class_name); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | int main() { |
| 42 | Isa *my_class_isa = (Isa *)malloc(size: sizeof(Isa)); |
| 43 | memset(s: my_class_isa, c: 0x77, n: sizeof(Isa)); |
| 44 | my_class_isa->class_name = "MyClass" ; |
| 45 | |
| 46 | MyClass *my_object = (MyClass *)malloc(size: sizeof(MyClass)); |
| 47 | memset(s: my_object, c: 0x88, n: sizeof(MyClass)); |
| 48 | my_object->isa = my_class_isa; |
| 49 | my_object->data = 42; |
| 50 | |
| 51 | my_object->print_my_class_name(); |
| 52 | // CHECK-SCRIBBLE: class name: MyClass |
| 53 | // CHECK-NOSCRIBBLE: class name: MyClass |
| 54 | |
| 55 | free(ptr: my_object); |
| 56 | |
| 57 | my_object->print_my_class_name(); |
| 58 | // CHECK-NOSCRIBBLE: class name: MyClass |
| 59 | // CHECK-SCRIBBLE: isa = {{(0x)?}}{{5555555555555555|55555555}} |
| 60 | |
| 61 | fprintf(stderr, format: "okthxbai!\n" ); |
| 62 | // CHECK-SCRIBBLE: okthxbai! |
| 63 | // CHECK-NOSCRIBBLE: okthxbai! |
| 64 | free(ptr: my_class_isa); |
| 65 | } |
| 66 | |