6
6
// License. See LICENSE.TXT for details.
7
7
//
8
8
// ===----------------------------------------------------------------------===//
9
+ #include < stdint.h>
9
10
#include < stdio.h>
11
+ #include < stdlib.h>
12
+
13
+ #include < string>
10
14
11
15
#include < gtest/gtest.h>
12
16
17
+ #if __LP64__ || defined(_WIN64)
18
+ # define SANITIZER_WORDSIZE 64
19
+ #else
20
+ # define SANITIZER_WORDSIZE 32
21
+ #endif
22
+
13
23
#define NOINLINE __attribute__ ((noinline))
14
24
15
25
typedef uint8_t U1;
@@ -26,6 +36,16 @@ inline void break_optimization(void *arg) {
26
36
#endif
27
37
}
28
38
39
+ // This function returns its parameter but in such a way that compiler
40
+ // can not prove it.
41
+ template <class T >
42
+ NOINLINE
43
+ static T Ident (T t) {
44
+ T ret = t;
45
+ break_optimization (&ret);
46
+ return ret;
47
+ }
48
+
29
49
NOINLINE void *malloc_fff (size_t size) {
30
50
void *res = malloc/* */ (size); break_optimization (0 ); return res;}
31
51
NOINLINE void *malloc_eee (size_t size) {
@@ -48,6 +68,14 @@ NOINLINE void asan_write(T *a) {
48
68
*a = 0 ;
49
69
}
50
70
71
+ NOINLINE void asan_write_sized_aligned (uint8_t *p, size_t size) {
72
+ EXPECT_EQ (0U , ((uintptr_t )p % size));
73
+ if (size == 1 ) asan_write ((uint8_t *)p);
74
+ else if (size == 2 ) asan_write ((uint16_t *)p);
75
+ else if (size == 4 ) asan_write ((uint32_t *)p);
76
+ else if (size == 8 ) asan_write ((uint64_t *)p);
77
+ }
78
+
51
79
template <typename T>
52
80
NOINLINE void oob_test (int size, int off) {
53
81
char *p = (char *)malloc_aaa (size);
@@ -57,41 +85,106 @@ NOINLINE void oob_test(int size, int off) {
57
85
free_aaa (p);
58
86
}
59
87
88
+ static std::string GetLeftOOBMessage (int off) {
89
+ char str[100 ];
90
+ sprintf (str, " is located.*%d byte.*before" , off);
91
+ return str;
92
+ }
93
+
94
+ static std::string GetRightOOBMessage (int off) {
95
+ char str[100 ];
96
+ #if !defined(_WIN32)
97
+ // FIXME: Fix PR42868 and remove SEGV match.
98
+ sprintf (str, " is located.*%d byte.*after|SEGV" , off);
99
+ #else
100
+ // `|` doesn't work in googletest's regexes on Windows,
101
+ // see googletest/docs/advanced.md#regular-expression-syntax
102
+ // But it's not needed on Windows anyways.
103
+ sprintf (str, " is located.*%d byte.*after" , off);
104
+ #endif
105
+ return str;
106
+ }
107
+
60
108
template <typename T>
61
109
void OOBTest () {
62
- char expected_str[100 ];
63
110
for (int size = sizeof (T); size < 20 ; size += 5 ) {
64
- for (int i = -5 ; i < 0 ; i++) {
65
- const char *str =
66
- " is located.*%d byte.*to the left" ;
67
- sprintf (expected_str, str, abs (i));
68
- EXPECT_DEATH (oob_test<T>(size, i), expected_str);
69
- }
111
+ for (int i = -5 ; i < 0 ; i++)
112
+ EXPECT_DEATH (oob_test<T>(size, i), GetLeftOOBMessage (-i));
70
113
71
114
for (int i = 0 ; i < (int )(size - sizeof (T) + 1 ); i++)
72
115
oob_test<T>(size, i);
73
116
74
117
for (int i = size - sizeof (T) + 1 ; i <= (int )(size + 2 * sizeof (T)); i++) {
75
- const char *str =
76
- " is located.*%d byte.*to the right" ;
77
- int off = i >= size ? (i - size) : 0 ;
78
118
// we don't catch unaligned partially OOB accesses.
79
119
if (i % sizeof (T)) continue ;
80
- sprintf (expected_str, str, off) ;
81
- EXPECT_DEATH (oob_test<T>(size, i), expected_str );
120
+ int off = i >= size ? (i - size) : 0 ;
121
+ EXPECT_DEATH (oob_test<T>(size, i), GetRightOOBMessage (off) );
82
122
}
83
123
}
84
124
85
- EXPECT_DEATH (oob_test<T>(kLargeMalloc , -1 ),
86
- " is located.*1 byte.*to the left" );
87
- EXPECT_DEATH (oob_test<T>(kLargeMalloc , kLargeMalloc ),
88
- " is located.*0 byte.*to the right" );
125
+ EXPECT_DEATH (oob_test<T>(kLargeMalloc , -1 ), GetLeftOOBMessage (1 ));
126
+ EXPECT_DEATH (oob_test<T>(kLargeMalloc , kLargeMalloc ), GetRightOOBMessage (0 ));
89
127
}
90
128
129
+ // TODO(glider): the following tests are EXTREMELY slow on Darwin:
130
+ // AddressSanitizer.OOB_char (125503 ms)
131
+ // AddressSanitizer.OOB_int (126890 ms)
132
+ // AddressSanitizer.OOBRightTest (315605 ms)
133
+ // AddressSanitizer.SimpleStackTest (366559 ms)
134
+
91
135
TEST (AddressSanitizer, OOB_char) {
92
136
OOBTest<U1>();
93
137
}
94
138
95
139
TEST (AddressSanitizer, OOB_int) {
96
140
OOBTest<U4>();
97
141
}
142
+
143
+ TEST (AddressSanitizer, OOBRightTest) {
144
+ size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4 ;
145
+ for (size_t access_size = 1 ; access_size <= max_access_size;
146
+ access_size *= 2 ) {
147
+ for (size_t alloc_size = 1 ; alloc_size <= 8 ; alloc_size++) {
148
+ for (size_t offset = 0 ; offset <= 8 ; offset += access_size) {
149
+ void *p = malloc (alloc_size);
150
+ // allocated: [p, p + alloc_size)
151
+ // accessed: [p + offset, p + offset + access_size)
152
+ uint8_t *addr = (uint8_t *)p + offset;
153
+ if (offset + access_size <= alloc_size) {
154
+ asan_write_sized_aligned (addr, access_size);
155
+ } else {
156
+ int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0 ;
157
+ EXPECT_DEATH (asan_write_sized_aligned (addr, access_size),
158
+ GetRightOOBMessage (outside_bytes));
159
+ }
160
+ free (p);
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ TEST (AddressSanitizer, LargeOOBRightTest) {
167
+ size_t large_power_of_two = 1 << 19 ;
168
+ for (size_t i = 16 ; i <= 256 ; i *= 2 ) {
169
+ size_t size = large_power_of_two - i;
170
+ char *p = Ident (new char [size]);
171
+ EXPECT_DEATH (p[size] = 0 , GetRightOOBMessage (0 ));
172
+ delete [] p;
173
+ }
174
+ }
175
+
176
+ TEST (AddressSanitizer, DISABLED_DemoOOBLeftLow) {
177
+ oob_test<U1>(10 , -1 );
178
+ }
179
+
180
+ TEST (AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
181
+ oob_test<U1>(kLargeMalloc , -1 );
182
+ }
183
+
184
+ TEST (AddressSanitizer, DISABLED_DemoOOBRightLow) {
185
+ oob_test<U1>(10 , 10 );
186
+ }
187
+
188
+ TEST (AddressSanitizer, DISABLED_DemoOOBRightHigh) {
189
+ oob_test<U1>(kLargeMalloc , kLargeMalloc );
190
+ }
0 commit comments