1 | // Verifies that speculative loads from unions do not happen under asan. |
2 | // RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 |
3 | // RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 |
4 | // RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 |
5 | // RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 |
6 | |
7 | #include <sanitizer/asan_interface.h> |
8 | |
9 | struct S { |
10 | struct _long { |
11 | void* _pad; |
12 | const char* _ptr; |
13 | }; |
14 | |
15 | struct _short { |
16 | unsigned char _size; |
17 | char _ch[23]; |
18 | }; |
19 | |
20 | union { |
21 | _short _s; |
22 | _long _l; |
23 | } _data; |
24 | |
25 | S() { |
26 | _data._s._size = 0; |
27 | __asan_poison_memory_region(addr: _data._s._ch, size: 23); |
28 | } |
29 | |
30 | ~S() { |
31 | __asan_unpoison_memory_region(addr: _data._s._ch, size: 23); |
32 | } |
33 | |
34 | bool is_long() const { |
35 | return _data._s._size & 1; |
36 | } |
37 | |
38 | const char* get_pointer() const { |
39 | return is_long() ? _data._l._ptr : _data._s._ch; |
40 | } |
41 | }; |
42 | |
43 | |
44 | inline void side_effect(const void *arg) { |
45 | __asm__ __volatile__("" : : "r" (arg) : "memory" ); |
46 | } |
47 | |
48 | int main(int argc, char **argv) { |
49 | S s; |
50 | side_effect(arg: &s); // optimizer is too smart otherwise |
51 | const char *ptr = s.get_pointer(); |
52 | side_effect(arg: ptr); // force use ptr |
53 | return 0; |
54 | } |
55 | |