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 | |