annotate gcc/asan.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* AddressSanitizer, a fast memory error detector.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2012-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
3 Contributed by Kostya Serebryany <kcc@google.com>
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
8 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
9 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
10 version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
15 for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21
kono
parents:
diff changeset
22 #include "config.h"
kono
parents:
diff changeset
23 #include "system.h"
kono
parents:
diff changeset
24 #include "coretypes.h"
kono
parents:
diff changeset
25 #include "backend.h"
kono
parents:
diff changeset
26 #include "target.h"
kono
parents:
diff changeset
27 #include "rtl.h"
kono
parents:
diff changeset
28 #include "tree.h"
kono
parents:
diff changeset
29 #include "gimple.h"
kono
parents:
diff changeset
30 #include "cfghooks.h"
kono
parents:
diff changeset
31 #include "alloc-pool.h"
kono
parents:
diff changeset
32 #include "tree-pass.h"
kono
parents:
diff changeset
33 #include "memmodel.h"
kono
parents:
diff changeset
34 #include "tm_p.h"
kono
parents:
diff changeset
35 #include "ssa.h"
kono
parents:
diff changeset
36 #include "stringpool.h"
kono
parents:
diff changeset
37 #include "tree-ssanames.h"
kono
parents:
diff changeset
38 #include "optabs.h"
kono
parents:
diff changeset
39 #include "emit-rtl.h"
kono
parents:
diff changeset
40 #include "cgraph.h"
kono
parents:
diff changeset
41 #include "gimple-pretty-print.h"
kono
parents:
diff changeset
42 #include "alias.h"
kono
parents:
diff changeset
43 #include "fold-const.h"
kono
parents:
diff changeset
44 #include "cfganal.h"
kono
parents:
diff changeset
45 #include "gimplify.h"
kono
parents:
diff changeset
46 #include "gimple-iterator.h"
kono
parents:
diff changeset
47 #include "varasm.h"
kono
parents:
diff changeset
48 #include "stor-layout.h"
kono
parents:
diff changeset
49 #include "tree-iterator.h"
kono
parents:
diff changeset
50 #include "stringpool.h"
kono
parents:
diff changeset
51 #include "attribs.h"
kono
parents:
diff changeset
52 #include "asan.h"
kono
parents:
diff changeset
53 #include "dojump.h"
kono
parents:
diff changeset
54 #include "explow.h"
kono
parents:
diff changeset
55 #include "expr.h"
kono
parents:
diff changeset
56 #include "output.h"
kono
parents:
diff changeset
57 #include "langhooks.h"
kono
parents:
diff changeset
58 #include "cfgloop.h"
kono
parents:
diff changeset
59 #include "gimple-builder.h"
kono
parents:
diff changeset
60 #include "gimple-fold.h"
kono
parents:
diff changeset
61 #include "ubsan.h"
kono
parents:
diff changeset
62 #include "builtins.h"
kono
parents:
diff changeset
63 #include "fnmatch.h"
kono
parents:
diff changeset
64 #include "tree-inline.h"
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
kono
parents:
diff changeset
67 with <2x slowdown on average.
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 The tool consists of two parts:
kono
parents:
diff changeset
70 instrumentation module (this file) and a run-time library.
kono
parents:
diff changeset
71 The instrumentation module adds a run-time check before every memory insn.
kono
parents:
diff changeset
72 For a 8- or 16- byte load accessing address X:
kono
parents:
diff changeset
73 ShadowAddr = (X >> 3) + Offset
kono
parents:
diff changeset
74 ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access.
kono
parents:
diff changeset
75 if (ShadowValue)
kono
parents:
diff changeset
76 __asan_report_load8(X);
kono
parents:
diff changeset
77 For a load of N bytes (N=1, 2 or 4) from address X:
kono
parents:
diff changeset
78 ShadowAddr = (X >> 3) + Offset
kono
parents:
diff changeset
79 ShadowValue = *(char*)ShadowAddr;
kono
parents:
diff changeset
80 if (ShadowValue)
kono
parents:
diff changeset
81 if ((X & 7) + N - 1 > ShadowValue)
kono
parents:
diff changeset
82 __asan_report_loadN(X);
kono
parents:
diff changeset
83 Stores are instrumented similarly, but using __asan_report_storeN functions.
kono
parents:
diff changeset
84 A call too __asan_init_vN() is inserted to the list of module CTORs.
kono
parents:
diff changeset
85 N is the version number of the AddressSanitizer API. The changes between the
kono
parents:
diff changeset
86 API versions are listed in libsanitizer/asan/asan_interface_internal.h.
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 The run-time library redefines malloc (so that redzone are inserted around
kono
parents:
diff changeset
89 the allocated memory) and free (so that reuse of free-ed memory is delayed),
kono
parents:
diff changeset
90 provides __asan_report* and __asan_init_vN functions.
kono
parents:
diff changeset
91
kono
parents:
diff changeset
92 Read more:
kono
parents:
diff changeset
93 http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 The current implementation supports detection of out-of-bounds and
kono
parents:
diff changeset
96 use-after-free in the heap, on the stack and for global variables.
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 [Protection of stack variables]
kono
parents:
diff changeset
99
kono
parents:
diff changeset
100 To understand how detection of out-of-bounds and use-after-free works
kono
parents:
diff changeset
101 for stack variables, lets look at this example on x86_64 where the
kono
parents:
diff changeset
102 stack grows downward:
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 int
kono
parents:
diff changeset
105 foo ()
kono
parents:
diff changeset
106 {
kono
parents:
diff changeset
107 char a[23] = {0};
kono
parents:
diff changeset
108 int b[2] = {0};
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 a[5] = 1;
kono
parents:
diff changeset
111 b[1] = 2;
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 return a[5] + b[1];
kono
parents:
diff changeset
114 }
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 For this function, the stack protected by asan will be organized as
kono
parents:
diff changeset
117 follows, from the top of the stack to the bottom:
kono
parents:
diff changeset
118
kono
parents:
diff changeset
119 Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
kono
parents:
diff changeset
120
kono
parents:
diff changeset
121 Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make
kono
parents:
diff changeset
122 the next slot be 32 bytes aligned; this one is called Partial
kono
parents:
diff changeset
123 Redzone; this 32 bytes alignment is an asan constraint]
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 Slot 3/ [24 bytes for variable 'a']
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2]
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 Slot 6/ [8 bytes for variable 'b']
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called
kono
parents:
diff changeset
134 'LEFT RedZone']
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 The 32 bytes of LEFT red zone at the bottom of the stack can be
kono
parents:
diff changeset
137 decomposed as such:
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 1/ The first 8 bytes contain a magical asan number that is always
kono
parents:
diff changeset
140 0x41B58AB3.
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 2/ The following 8 bytes contains a pointer to a string (to be
kono
parents:
diff changeset
143 parsed at runtime by the runtime asan library), which format is
kono
parents:
diff changeset
144 the following:
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 "<function-name> <space> <num-of-variables-on-the-stack>
kono
parents:
diff changeset
147 (<32-bytes-aligned-offset-in-bytes-of-variable> <space>
kono
parents:
diff changeset
148 <length-of-var-in-bytes> ){n} "
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 where '(...){n}' means the content inside the parenthesis occurs 'n'
kono
parents:
diff changeset
151 times, with 'n' being the number of variables on the stack.
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 3/ The following 8 bytes contain the PC of the current function which
kono
parents:
diff changeset
154 will be used by the run-time library to print an error message.
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 4/ The following 8 bytes are reserved for internal use by the run-time.
kono
parents:
diff changeset
157
kono
parents:
diff changeset
158 The shadow memory for that stack layout is going to look like this:
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 - content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1.
kono
parents:
diff changeset
161 The F1 byte pattern is a magic number called
kono
parents:
diff changeset
162 ASAN_STACK_MAGIC_LEFT and is a way for the runtime to know that
kono
parents:
diff changeset
163 the memory for that shadow byte is part of a the LEFT red zone
kono
parents:
diff changeset
164 intended to seat at the bottom of the variables on the stack.
kono
parents:
diff changeset
165
kono
parents:
diff changeset
166 - content of shadow memory 8 bytes for slots 6 and 5:
kono
parents:
diff changeset
167 0xF4F4F400. The F4 byte pattern is a magic number
kono
parents:
diff changeset
168 called ASAN_STACK_MAGIC_PARTIAL. It flags the fact that the
kono
parents:
diff changeset
169 memory region for this shadow byte is a PARTIAL red zone
kono
parents:
diff changeset
170 intended to pad a variable A, so that the slot following
kono
parents:
diff changeset
171 {A,padding} is 32 bytes aligned.
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 Note that the fact that the least significant byte of this
kono
parents:
diff changeset
174 shadow memory content is 00 means that 8 bytes of its
kono
parents:
diff changeset
175 corresponding memory (which corresponds to the memory of
kono
parents:
diff changeset
176 variable 'b') is addressable.
kono
parents:
diff changeset
177
kono
parents:
diff changeset
178 - content of shadow memory 8 bytes for slot 4: 0xF2F2F2F2.
kono
parents:
diff changeset
179 The F2 byte pattern is a magic number called
kono
parents:
diff changeset
180 ASAN_STACK_MAGIC_MIDDLE. It flags the fact that the memory
kono
parents:
diff changeset
181 region for this shadow byte is a MIDDLE red zone intended to
kono
parents:
diff changeset
182 seat between two 32 aligned slots of {variable,padding}.
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 - content of shadow memory 8 bytes for slot 3 and 2:
kono
parents:
diff changeset
185 0xF4000000. This represents is the concatenation of
kono
parents:
diff changeset
186 variable 'a' and the partial red zone following it, like what we
kono
parents:
diff changeset
187 had for variable 'b'. The least significant 3 bytes being 00
kono
parents:
diff changeset
188 means that the 3 bytes of variable 'a' are addressable.
kono
parents:
diff changeset
189
kono
parents:
diff changeset
190 - content of shadow memory 8 bytes for slot 1: 0xF3F3F3F3.
kono
parents:
diff changeset
191 The F3 byte pattern is a magic number called
kono
parents:
diff changeset
192 ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory
kono
parents:
diff changeset
193 region for this shadow byte is a RIGHT red zone intended to seat
kono
parents:
diff changeset
194 at the top of the variables of the stack.
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 Note that the real variable layout is done in expand_used_vars in
kono
parents:
diff changeset
197 cfgexpand.c. As far as Address Sanitizer is concerned, it lays out
kono
parents:
diff changeset
198 stack variables as well as the different red zones, emits some
kono
parents:
diff changeset
199 prologue code to populate the shadow memory as to poison (mark as
kono
parents:
diff changeset
200 non-accessible) the regions of the red zones and mark the regions of
kono
parents:
diff changeset
201 stack variables as accessible, and emit some epilogue code to
kono
parents:
diff changeset
202 un-poison (mark as accessible) the regions of red zones right before
kono
parents:
diff changeset
203 the function exits.
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 [Protection of global variables]
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 The basic idea is to insert a red zone between two global variables
kono
parents:
diff changeset
208 and install a constructor function that calls the asan runtime to do
kono
parents:
diff changeset
209 the populating of the relevant shadow memory regions at load time.
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 So the global variables are laid out as to insert a red zone between
kono
parents:
diff changeset
212 them. The size of the red zones is so that each variable starts on a
kono
parents:
diff changeset
213 32 bytes boundary.
kono
parents:
diff changeset
214
kono
parents:
diff changeset
215 Then a constructor function is installed so that, for each global
kono
parents:
diff changeset
216 variable, it calls the runtime asan library function
kono
parents:
diff changeset
217 __asan_register_globals_with an instance of this type:
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 struct __asan_global
kono
parents:
diff changeset
220 {
kono
parents:
diff changeset
221 // Address of the beginning of the global variable.
kono
parents:
diff changeset
222 const void *__beg;
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 // Initial size of the global variable.
kono
parents:
diff changeset
225 uptr __size;
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 // Size of the global variable + size of the red zone. This
kono
parents:
diff changeset
228 // size is 32 bytes aligned.
kono
parents:
diff changeset
229 uptr __size_with_redzone;
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 // Name of the global variable.
kono
parents:
diff changeset
232 const void *__name;
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 // Name of the module where the global variable is declared.
kono
parents:
diff changeset
235 const void *__module_name;
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 // 1 if it has dynamic initialization, 0 otherwise.
kono
parents:
diff changeset
238 uptr __has_dynamic_init;
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 // A pointer to struct that contains source location, could be NULL.
kono
parents:
diff changeset
241 __asan_global_source_location *__location;
kono
parents:
diff changeset
242 }
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 A destructor function that calls the runtime asan library function
kono
parents:
diff changeset
245 _asan_unregister_globals is also installed. */
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 static unsigned HOST_WIDE_INT asan_shadow_offset_value;
kono
parents:
diff changeset
248 static bool asan_shadow_offset_computed;
kono
parents:
diff changeset
249 static vec<char *> sanitized_sections;
kono
parents:
diff changeset
250 static tree last_alloca_addr;
kono
parents:
diff changeset
251
kono
parents:
diff changeset
252 /* Set of variable declarations that are going to be guarded by
kono
parents:
diff changeset
253 use-after-scope sanitizer. */
kono
parents:
diff changeset
254
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
255 hash_set<tree> *asan_handled_variables = NULL;
111
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 hash_set <tree> *asan_used_labels = NULL;
kono
parents:
diff changeset
258
kono
parents:
diff changeset
259 /* Sets shadow offset to value in string VAL. */
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 bool
kono
parents:
diff changeset
262 set_asan_shadow_offset (const char *val)
kono
parents:
diff changeset
263 {
kono
parents:
diff changeset
264 char *endp;
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 errno = 0;
kono
parents:
diff changeset
267 #ifdef HAVE_LONG_LONG
kono
parents:
diff changeset
268 asan_shadow_offset_value = strtoull (val, &endp, 0);
kono
parents:
diff changeset
269 #else
kono
parents:
diff changeset
270 asan_shadow_offset_value = strtoul (val, &endp, 0);
kono
parents:
diff changeset
271 #endif
kono
parents:
diff changeset
272 if (!(*val != '\0' && *endp == '\0' && errno == 0))
kono
parents:
diff changeset
273 return false;
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 asan_shadow_offset_computed = true;
kono
parents:
diff changeset
276
kono
parents:
diff changeset
277 return true;
kono
parents:
diff changeset
278 }
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 /* Set list of user-defined sections that need to be sanitized. */
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 void
kono
parents:
diff changeset
283 set_sanitized_sections (const char *sections)
kono
parents:
diff changeset
284 {
kono
parents:
diff changeset
285 char *pat;
kono
parents:
diff changeset
286 unsigned i;
kono
parents:
diff changeset
287 FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
kono
parents:
diff changeset
288 free (pat);
kono
parents:
diff changeset
289 sanitized_sections.truncate (0);
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 for (const char *s = sections; *s; )
kono
parents:
diff changeset
292 {
kono
parents:
diff changeset
293 const char *end;
kono
parents:
diff changeset
294 for (end = s; *end && *end != ','; ++end);
kono
parents:
diff changeset
295 size_t len = end - s;
kono
parents:
diff changeset
296 sanitized_sections.safe_push (xstrndup (s, len));
kono
parents:
diff changeset
297 s = *end ? end + 1 : end;
kono
parents:
diff changeset
298 }
kono
parents:
diff changeset
299 }
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 bool
kono
parents:
diff changeset
302 asan_mark_p (gimple *stmt, enum asan_mark_flags flag)
kono
parents:
diff changeset
303 {
kono
parents:
diff changeset
304 return (gimple_call_internal_p (stmt, IFN_ASAN_MARK)
kono
parents:
diff changeset
305 && tree_to_uhwi (gimple_call_arg (stmt, 0)) == flag);
kono
parents:
diff changeset
306 }
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 bool
kono
parents:
diff changeset
309 asan_sanitize_stack_p (void)
kono
parents:
diff changeset
310 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
311 return (sanitize_flags_p (SANITIZE_ADDRESS) && param_asan_stack);
111
kono
parents:
diff changeset
312 }
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 bool
kono
parents:
diff changeset
315 asan_sanitize_allocas_p (void)
kono
parents:
diff changeset
316 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
317 return (asan_sanitize_stack_p () && param_asan_protect_allocas);
111
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319
kono
parents:
diff changeset
320 /* Checks whether section SEC should be sanitized. */
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 static bool
kono
parents:
diff changeset
323 section_sanitized_p (const char *sec)
kono
parents:
diff changeset
324 {
kono
parents:
diff changeset
325 char *pat;
kono
parents:
diff changeset
326 unsigned i;
kono
parents:
diff changeset
327 FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
kono
parents:
diff changeset
328 if (fnmatch (pat, sec, FNM_PERIOD) == 0)
kono
parents:
diff changeset
329 return true;
kono
parents:
diff changeset
330 return false;
kono
parents:
diff changeset
331 }
kono
parents:
diff changeset
332
kono
parents:
diff changeset
333 /* Returns Asan shadow offset. */
kono
parents:
diff changeset
334
kono
parents:
diff changeset
335 static unsigned HOST_WIDE_INT
kono
parents:
diff changeset
336 asan_shadow_offset ()
kono
parents:
diff changeset
337 {
kono
parents:
diff changeset
338 if (!asan_shadow_offset_computed)
kono
parents:
diff changeset
339 {
kono
parents:
diff changeset
340 asan_shadow_offset_computed = true;
kono
parents:
diff changeset
341 asan_shadow_offset_value = targetm.asan_shadow_offset ();
kono
parents:
diff changeset
342 }
kono
parents:
diff changeset
343 return asan_shadow_offset_value;
kono
parents:
diff changeset
344 }
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 alias_set_type asan_shadow_set = -1;
kono
parents:
diff changeset
347
kono
parents:
diff changeset
348 /* Pointer types to 1, 2 or 4 byte integers in shadow memory. A separate
kono
parents:
diff changeset
349 alias set is used for all shadow memory accesses. */
kono
parents:
diff changeset
350 static GTY(()) tree shadow_ptr_types[3];
kono
parents:
diff changeset
351
kono
parents:
diff changeset
352 /* Decl for __asan_option_detect_stack_use_after_return. */
kono
parents:
diff changeset
353 static GTY(()) tree asan_detect_stack_use_after_return;
kono
parents:
diff changeset
354
kono
parents:
diff changeset
355 /* Hashtable support for memory references used by gimple
kono
parents:
diff changeset
356 statements. */
kono
parents:
diff changeset
357
kono
parents:
diff changeset
358 /* This type represents a reference to a memory region. */
kono
parents:
diff changeset
359 struct asan_mem_ref
kono
parents:
diff changeset
360 {
kono
parents:
diff changeset
361 /* The expression of the beginning of the memory region. */
kono
parents:
diff changeset
362 tree start;
kono
parents:
diff changeset
363
kono
parents:
diff changeset
364 /* The size of the access. */
kono
parents:
diff changeset
365 HOST_WIDE_INT access_size;
kono
parents:
diff changeset
366 };
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 object_allocator <asan_mem_ref> asan_mem_ref_pool ("asan_mem_ref");
kono
parents:
diff changeset
369
kono
parents:
diff changeset
370 /* Initializes an instance of asan_mem_ref. */
kono
parents:
diff changeset
371
kono
parents:
diff changeset
372 static void
kono
parents:
diff changeset
373 asan_mem_ref_init (asan_mem_ref *ref, tree start, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
374 {
kono
parents:
diff changeset
375 ref->start = start;
kono
parents:
diff changeset
376 ref->access_size = access_size;
kono
parents:
diff changeset
377 }
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 /* Allocates memory for an instance of asan_mem_ref into the memory
kono
parents:
diff changeset
380 pool returned by asan_mem_ref_get_alloc_pool and initialize it.
kono
parents:
diff changeset
381 START is the address of (or the expression pointing to) the
kono
parents:
diff changeset
382 beginning of memory reference. ACCESS_SIZE is the size of the
kono
parents:
diff changeset
383 access to the referenced memory. */
kono
parents:
diff changeset
384
kono
parents:
diff changeset
385 static asan_mem_ref*
kono
parents:
diff changeset
386 asan_mem_ref_new (tree start, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
387 {
kono
parents:
diff changeset
388 asan_mem_ref *ref = asan_mem_ref_pool.allocate ();
kono
parents:
diff changeset
389
kono
parents:
diff changeset
390 asan_mem_ref_init (ref, start, access_size);
kono
parents:
diff changeset
391 return ref;
kono
parents:
diff changeset
392 }
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 /* This builds and returns a pointer to the end of the memory region
kono
parents:
diff changeset
395 that starts at START and of length LEN. */
kono
parents:
diff changeset
396
kono
parents:
diff changeset
397 tree
kono
parents:
diff changeset
398 asan_mem_ref_get_end (tree start, tree len)
kono
parents:
diff changeset
399 {
kono
parents:
diff changeset
400 if (len == NULL_TREE || integer_zerop (len))
kono
parents:
diff changeset
401 return start;
kono
parents:
diff changeset
402
kono
parents:
diff changeset
403 if (!ptrofftype_p (len))
kono
parents:
diff changeset
404 len = convert_to_ptrofftype (len);
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (start), start, len);
kono
parents:
diff changeset
407 }
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 /* Return a tree expression that represents the end of the referenced
kono
parents:
diff changeset
410 memory region. Beware that this function can actually build a new
kono
parents:
diff changeset
411 tree expression. */
kono
parents:
diff changeset
412
kono
parents:
diff changeset
413 tree
kono
parents:
diff changeset
414 asan_mem_ref_get_end (const asan_mem_ref *ref, tree len)
kono
parents:
diff changeset
415 {
kono
parents:
diff changeset
416 return asan_mem_ref_get_end (ref->start, len);
kono
parents:
diff changeset
417 }
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 struct asan_mem_ref_hasher : nofree_ptr_hash <asan_mem_ref>
kono
parents:
diff changeset
420 {
kono
parents:
diff changeset
421 static inline hashval_t hash (const asan_mem_ref *);
kono
parents:
diff changeset
422 static inline bool equal (const asan_mem_ref *, const asan_mem_ref *);
kono
parents:
diff changeset
423 };
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 /* Hash a memory reference. */
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 inline hashval_t
kono
parents:
diff changeset
428 asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref)
kono
parents:
diff changeset
429 {
kono
parents:
diff changeset
430 return iterative_hash_expr (mem_ref->start, 0);
kono
parents:
diff changeset
431 }
kono
parents:
diff changeset
432
kono
parents:
diff changeset
433 /* Compare two memory references. We accept the length of either
kono
parents:
diff changeset
434 memory references to be NULL_TREE. */
kono
parents:
diff changeset
435
kono
parents:
diff changeset
436 inline bool
kono
parents:
diff changeset
437 asan_mem_ref_hasher::equal (const asan_mem_ref *m1,
kono
parents:
diff changeset
438 const asan_mem_ref *m2)
kono
parents:
diff changeset
439 {
kono
parents:
diff changeset
440 return operand_equal_p (m1->start, m2->start, 0);
kono
parents:
diff changeset
441 }
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 static hash_table<asan_mem_ref_hasher> *asan_mem_ref_ht;
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 /* Returns a reference to the hash table containing memory references.
kono
parents:
diff changeset
446 This function ensures that the hash table is created. Note that
kono
parents:
diff changeset
447 this hash table is updated by the function
kono
parents:
diff changeset
448 update_mem_ref_hash_table. */
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 static hash_table<asan_mem_ref_hasher> *
kono
parents:
diff changeset
451 get_mem_ref_hash_table ()
kono
parents:
diff changeset
452 {
kono
parents:
diff changeset
453 if (!asan_mem_ref_ht)
kono
parents:
diff changeset
454 asan_mem_ref_ht = new hash_table<asan_mem_ref_hasher> (10);
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 return asan_mem_ref_ht;
kono
parents:
diff changeset
457 }
kono
parents:
diff changeset
458
kono
parents:
diff changeset
459 /* Clear all entries from the memory references hash table. */
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 static void
kono
parents:
diff changeset
462 empty_mem_ref_hash_table ()
kono
parents:
diff changeset
463 {
kono
parents:
diff changeset
464 if (asan_mem_ref_ht)
kono
parents:
diff changeset
465 asan_mem_ref_ht->empty ();
kono
parents:
diff changeset
466 }
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 /* Free the memory references hash table. */
kono
parents:
diff changeset
469
kono
parents:
diff changeset
470 static void
kono
parents:
diff changeset
471 free_mem_ref_resources ()
kono
parents:
diff changeset
472 {
kono
parents:
diff changeset
473 delete asan_mem_ref_ht;
kono
parents:
diff changeset
474 asan_mem_ref_ht = NULL;
kono
parents:
diff changeset
475
kono
parents:
diff changeset
476 asan_mem_ref_pool.release ();
kono
parents:
diff changeset
477 }
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 /* Return true iff the memory reference REF has been instrumented. */
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 static bool
kono
parents:
diff changeset
482 has_mem_ref_been_instrumented (tree ref, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
483 {
kono
parents:
diff changeset
484 asan_mem_ref r;
kono
parents:
diff changeset
485 asan_mem_ref_init (&r, ref, access_size);
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 asan_mem_ref *saved_ref = get_mem_ref_hash_table ()->find (&r);
kono
parents:
diff changeset
488 return saved_ref && saved_ref->access_size >= access_size;
kono
parents:
diff changeset
489 }
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 /* Return true iff the memory reference REF has been instrumented. */
kono
parents:
diff changeset
492
kono
parents:
diff changeset
493 static bool
kono
parents:
diff changeset
494 has_mem_ref_been_instrumented (const asan_mem_ref *ref)
kono
parents:
diff changeset
495 {
kono
parents:
diff changeset
496 return has_mem_ref_been_instrumented (ref->start, ref->access_size);
kono
parents:
diff changeset
497 }
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 /* Return true iff access to memory region starting at REF and of
kono
parents:
diff changeset
500 length LEN has been instrumented. */
kono
parents:
diff changeset
501
kono
parents:
diff changeset
502 static bool
kono
parents:
diff changeset
503 has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
kono
parents:
diff changeset
504 {
kono
parents:
diff changeset
505 HOST_WIDE_INT size_in_bytes
kono
parents:
diff changeset
506 = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
kono
parents:
diff changeset
507
kono
parents:
diff changeset
508 return size_in_bytes != -1
kono
parents:
diff changeset
509 && has_mem_ref_been_instrumented (ref->start, size_in_bytes);
kono
parents:
diff changeset
510 }
kono
parents:
diff changeset
511
kono
parents:
diff changeset
512 /* Set REF to the memory reference present in a gimple assignment
kono
parents:
diff changeset
513 ASSIGNMENT. Return true upon successful completion, false
kono
parents:
diff changeset
514 otherwise. */
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 static bool
kono
parents:
diff changeset
517 get_mem_ref_of_assignment (const gassign *assignment,
kono
parents:
diff changeset
518 asan_mem_ref *ref,
kono
parents:
diff changeset
519 bool *ref_is_store)
kono
parents:
diff changeset
520 {
kono
parents:
diff changeset
521 gcc_assert (gimple_assign_single_p (assignment));
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 if (gimple_store_p (assignment)
kono
parents:
diff changeset
524 && !gimple_clobber_p (assignment))
kono
parents:
diff changeset
525 {
kono
parents:
diff changeset
526 ref->start = gimple_assign_lhs (assignment);
kono
parents:
diff changeset
527 *ref_is_store = true;
kono
parents:
diff changeset
528 }
kono
parents:
diff changeset
529 else if (gimple_assign_load_p (assignment))
kono
parents:
diff changeset
530 {
kono
parents:
diff changeset
531 ref->start = gimple_assign_rhs1 (assignment);
kono
parents:
diff changeset
532 *ref_is_store = false;
kono
parents:
diff changeset
533 }
kono
parents:
diff changeset
534 else
kono
parents:
diff changeset
535 return false;
kono
parents:
diff changeset
536
kono
parents:
diff changeset
537 ref->access_size = int_size_in_bytes (TREE_TYPE (ref->start));
kono
parents:
diff changeset
538 return true;
kono
parents:
diff changeset
539 }
kono
parents:
diff changeset
540
kono
parents:
diff changeset
541 /* Return address of last allocated dynamic alloca. */
kono
parents:
diff changeset
542
kono
parents:
diff changeset
543 static tree
kono
parents:
diff changeset
544 get_last_alloca_addr ()
kono
parents:
diff changeset
545 {
kono
parents:
diff changeset
546 if (last_alloca_addr)
kono
parents:
diff changeset
547 return last_alloca_addr;
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549 last_alloca_addr = create_tmp_reg (ptr_type_node, "last_alloca_addr");
kono
parents:
diff changeset
550 gassign *g = gimple_build_assign (last_alloca_addr, null_pointer_node);
kono
parents:
diff changeset
551 edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
kono
parents:
diff changeset
552 gsi_insert_on_edge_immediate (e, g);
kono
parents:
diff changeset
553 return last_alloca_addr;
kono
parents:
diff changeset
554 }
kono
parents:
diff changeset
555
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
556 /* Insert __asan_allocas_unpoison (top, bottom) call before
111
kono
parents:
diff changeset
557 __builtin_stack_restore (new_sp) call.
kono
parents:
diff changeset
558 The pseudocode of this routine should look like this:
kono
parents:
diff changeset
559 top = last_alloca_addr;
kono
parents:
diff changeset
560 bot = new_sp;
kono
parents:
diff changeset
561 __asan_allocas_unpoison (top, bot);
kono
parents:
diff changeset
562 last_alloca_addr = new_sp;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
563 __builtin_stack_restore (new_sp);
111
kono
parents:
diff changeset
564 In general, we can't use new_sp as bot parameter because on some
kono
parents:
diff changeset
565 architectures SP has non zero offset from dynamic stack area. Moreover, on
kono
parents:
diff changeset
566 some architectures this offset (STACK_DYNAMIC_OFFSET) becomes known for each
kono
parents:
diff changeset
567 particular function only after all callees were expanded to rtl.
kono
parents:
diff changeset
568 The most noticeable example is PowerPC{,64}, see
kono
parents:
diff changeset
569 http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#DYNAM-STACK.
kono
parents:
diff changeset
570 To overcome the issue we use following trick: pass new_sp as a second
kono
parents:
diff changeset
571 parameter to __asan_allocas_unpoison and rewrite it during expansion with
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
572 new_sp + (virtual_dynamic_stack_rtx - sp) later in
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
573 expand_asan_emit_allocas_unpoison function. */
111
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 static void
kono
parents:
diff changeset
576 handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
kono
parents:
diff changeset
577 {
kono
parents:
diff changeset
578 if (!iter || !asan_sanitize_allocas_p ())
kono
parents:
diff changeset
579 return;
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 tree last_alloca = get_last_alloca_addr ();
kono
parents:
diff changeset
582 tree restored_stack = gimple_call_arg (call, 0);
kono
parents:
diff changeset
583 tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
kono
parents:
diff changeset
584 gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
585 gsi_insert_before (iter, g, GSI_SAME_STMT);
111
kono
parents:
diff changeset
586 g = gimple_build_assign (last_alloca, restored_stack);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
587 gsi_insert_before (iter, g, GSI_SAME_STMT);
111
kono
parents:
diff changeset
588 }
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 /* Deploy and poison redzones around __builtin_alloca call. To do this, we
kono
parents:
diff changeset
591 should replace this call with another one with changed parameters and
kono
parents:
diff changeset
592 replace all its uses with new address, so
kono
parents:
diff changeset
593 addr = __builtin_alloca (old_size, align);
kono
parents:
diff changeset
594 is replaced by
kono
parents:
diff changeset
595 left_redzone_size = max (align, ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
596 Following two statements are optimized out if we know that
kono
parents:
diff changeset
597 old_size & (ASAN_RED_ZONE_SIZE - 1) == 0, i.e. alloca doesn't need partial
kono
parents:
diff changeset
598 redzone.
kono
parents:
diff changeset
599 misalign = old_size & (ASAN_RED_ZONE_SIZE - 1);
kono
parents:
diff changeset
600 partial_redzone_size = ASAN_RED_ZONE_SIZE - misalign;
kono
parents:
diff changeset
601 right_redzone_size = ASAN_RED_ZONE_SIZE;
kono
parents:
diff changeset
602 additional_size = left_redzone_size + partial_redzone_size +
kono
parents:
diff changeset
603 right_redzone_size;
kono
parents:
diff changeset
604 new_size = old_size + additional_size;
kono
parents:
diff changeset
605 new_alloca = __builtin_alloca (new_size, max (align, 32))
kono
parents:
diff changeset
606 __asan_alloca_poison (new_alloca, old_size)
kono
parents:
diff changeset
607 addr = new_alloca + max (align, ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
608 last_alloca_addr = new_alloca;
kono
parents:
diff changeset
609 ADDITIONAL_SIZE is added to make new memory allocation contain not only
kono
parents:
diff changeset
610 requested memory, but also left, partial and right redzones as well as some
kono
parents:
diff changeset
611 additional space, required by alignment. */
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 static void
kono
parents:
diff changeset
614 handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
kono
parents:
diff changeset
615 {
kono
parents:
diff changeset
616 if (!iter || !asan_sanitize_allocas_p ())
kono
parents:
diff changeset
617 return;
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 gassign *g;
kono
parents:
diff changeset
620 gcall *gg;
kono
parents:
diff changeset
621 const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
kono
parents:
diff changeset
622
kono
parents:
diff changeset
623 tree last_alloca = get_last_alloca_addr ();
kono
parents:
diff changeset
624 tree callee = gimple_call_fndecl (call);
kono
parents:
diff changeset
625 tree old_size = gimple_call_arg (call, 0);
kono
parents:
diff changeset
626 tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
kono
parents:
diff changeset
627 : ptr_type_node;
kono
parents:
diff changeset
628 tree partial_size = NULL_TREE;
kono
parents:
diff changeset
629 unsigned int align
kono
parents:
diff changeset
630 = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
kono
parents:
diff changeset
631 ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
kono
parents:
diff changeset
632
kono
parents:
diff changeset
633 /* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
kono
parents:
diff changeset
634 bytes of allocated space. Otherwise, align alloca to ASAN_RED_ZONE_SIZE
kono
parents:
diff changeset
635 manually. */
kono
parents:
diff changeset
636 align = MAX (align, ASAN_RED_ZONE_SIZE * BITS_PER_UNIT);
kono
parents:
diff changeset
637
kono
parents:
diff changeset
638 tree alloca_rz_mask = build_int_cst (size_type_node, redzone_mask);
kono
parents:
diff changeset
639 tree redzone_size = build_int_cst (size_type_node, ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
640
kono
parents:
diff changeset
641 /* Extract lower bits from old_size. */
kono
parents:
diff changeset
642 wide_int size_nonzero_bits = get_nonzero_bits (old_size);
kono
parents:
diff changeset
643 wide_int rz_mask
kono
parents:
diff changeset
644 = wi::uhwi (redzone_mask, wi::get_precision (size_nonzero_bits));
kono
parents:
diff changeset
645 wide_int old_size_lower_bits = wi::bit_and (size_nonzero_bits, rz_mask);
kono
parents:
diff changeset
646
kono
parents:
diff changeset
647 /* If alloca size is aligned to ASAN_RED_ZONE_SIZE, we don't need partial
kono
parents:
diff changeset
648 redzone. Otherwise, compute its size here. */
kono
parents:
diff changeset
649 if (wi::ne_p (old_size_lower_bits, 0))
kono
parents:
diff changeset
650 {
kono
parents:
diff changeset
651 /* misalign = size & (ASAN_RED_ZONE_SIZE - 1)
kono
parents:
diff changeset
652 partial_size = ASAN_RED_ZONE_SIZE - misalign. */
kono
parents:
diff changeset
653 g = gimple_build_assign (make_ssa_name (size_type_node, NULL),
kono
parents:
diff changeset
654 BIT_AND_EXPR, old_size, alloca_rz_mask);
kono
parents:
diff changeset
655 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
656 tree misalign = gimple_assign_lhs (g);
kono
parents:
diff changeset
657 g = gimple_build_assign (make_ssa_name (size_type_node, NULL), MINUS_EXPR,
kono
parents:
diff changeset
658 redzone_size, misalign);
kono
parents:
diff changeset
659 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
660 partial_size = gimple_assign_lhs (g);
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 /* additional_size = align + ASAN_RED_ZONE_SIZE. */
kono
parents:
diff changeset
664 tree additional_size = build_int_cst (size_type_node, align / BITS_PER_UNIT
kono
parents:
diff changeset
665 + ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
666 /* If alloca has partial redzone, include it to additional_size too. */
kono
parents:
diff changeset
667 if (partial_size)
kono
parents:
diff changeset
668 {
kono
parents:
diff changeset
669 /* additional_size += partial_size. */
kono
parents:
diff changeset
670 g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
kono
parents:
diff changeset
671 partial_size, additional_size);
kono
parents:
diff changeset
672 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
673 additional_size = gimple_assign_lhs (g);
kono
parents:
diff changeset
674 }
kono
parents:
diff changeset
675
kono
parents:
diff changeset
676 /* new_size = old_size + additional_size. */
kono
parents:
diff changeset
677 g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR, old_size,
kono
parents:
diff changeset
678 additional_size);
kono
parents:
diff changeset
679 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
680 tree new_size = gimple_assign_lhs (g);
kono
parents:
diff changeset
681
kono
parents:
diff changeset
682 /* Build new __builtin_alloca call:
kono
parents:
diff changeset
683 new_alloca_with_rz = __builtin_alloca (new_size, align). */
kono
parents:
diff changeset
684 tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
kono
parents:
diff changeset
685 gg = gimple_build_call (fn, 2, new_size,
kono
parents:
diff changeset
686 build_int_cst (size_type_node, align));
kono
parents:
diff changeset
687 tree new_alloca_with_rz = make_ssa_name (ptr_type, gg);
kono
parents:
diff changeset
688 gimple_call_set_lhs (gg, new_alloca_with_rz);
kono
parents:
diff changeset
689 gsi_insert_before (iter, gg, GSI_SAME_STMT);
kono
parents:
diff changeset
690
kono
parents:
diff changeset
691 /* new_alloca = new_alloca_with_rz + align. */
kono
parents:
diff changeset
692 g = gimple_build_assign (make_ssa_name (ptr_type), POINTER_PLUS_EXPR,
kono
parents:
diff changeset
693 new_alloca_with_rz,
kono
parents:
diff changeset
694 build_int_cst (size_type_node,
kono
parents:
diff changeset
695 align / BITS_PER_UNIT));
kono
parents:
diff changeset
696 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
697 tree new_alloca = gimple_assign_lhs (g);
kono
parents:
diff changeset
698
kono
parents:
diff changeset
699 /* Poison newly created alloca redzones:
kono
parents:
diff changeset
700 __asan_alloca_poison (new_alloca, old_size). */
kono
parents:
diff changeset
701 fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCA_POISON);
kono
parents:
diff changeset
702 gg = gimple_build_call (fn, 2, new_alloca, old_size);
kono
parents:
diff changeset
703 gsi_insert_before (iter, gg, GSI_SAME_STMT);
kono
parents:
diff changeset
704
kono
parents:
diff changeset
705 /* Save new_alloca_with_rz value into last_alloca to use it during
kono
parents:
diff changeset
706 allocas unpoisoning. */
kono
parents:
diff changeset
707 g = gimple_build_assign (last_alloca, new_alloca_with_rz);
kono
parents:
diff changeset
708 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
709
kono
parents:
diff changeset
710 /* Finally, replace old alloca ptr with NEW_ALLOCA. */
kono
parents:
diff changeset
711 replace_call_with_value (iter, new_alloca);
kono
parents:
diff changeset
712 }
kono
parents:
diff changeset
713
kono
parents:
diff changeset
714 /* Return the memory references contained in a gimple statement
kono
parents:
diff changeset
715 representing a builtin call that has to do with memory access. */
kono
parents:
diff changeset
716
kono
parents:
diff changeset
717 static bool
kono
parents:
diff changeset
718 get_mem_refs_of_builtin_call (gcall *call,
kono
parents:
diff changeset
719 asan_mem_ref *src0,
kono
parents:
diff changeset
720 tree *src0_len,
kono
parents:
diff changeset
721 bool *src0_is_store,
kono
parents:
diff changeset
722 asan_mem_ref *src1,
kono
parents:
diff changeset
723 tree *src1_len,
kono
parents:
diff changeset
724 bool *src1_is_store,
kono
parents:
diff changeset
725 asan_mem_ref *dst,
kono
parents:
diff changeset
726 tree *dst_len,
kono
parents:
diff changeset
727 bool *dst_is_store,
kono
parents:
diff changeset
728 bool *dest_is_deref,
kono
parents:
diff changeset
729 bool *intercepted_p,
kono
parents:
diff changeset
730 gimple_stmt_iterator *iter = NULL)
kono
parents:
diff changeset
731 {
kono
parents:
diff changeset
732 gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 tree callee = gimple_call_fndecl (call);
kono
parents:
diff changeset
735 tree source0 = NULL_TREE, source1 = NULL_TREE,
kono
parents:
diff changeset
736 dest = NULL_TREE, len = NULL_TREE;
kono
parents:
diff changeset
737 bool is_store = true, got_reference_p = false;
kono
parents:
diff changeset
738 HOST_WIDE_INT access_size = 1;
kono
parents:
diff changeset
739
kono
parents:
diff changeset
740 *intercepted_p = asan_intercepted_p ((DECL_FUNCTION_CODE (callee)));
kono
parents:
diff changeset
741
kono
parents:
diff changeset
742 switch (DECL_FUNCTION_CODE (callee))
kono
parents:
diff changeset
743 {
kono
parents:
diff changeset
744 /* (s, s, n) style memops. */
kono
parents:
diff changeset
745 case BUILT_IN_BCMP:
kono
parents:
diff changeset
746 case BUILT_IN_MEMCMP:
kono
parents:
diff changeset
747 source0 = gimple_call_arg (call, 0);
kono
parents:
diff changeset
748 source1 = gimple_call_arg (call, 1);
kono
parents:
diff changeset
749 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
750 break;
kono
parents:
diff changeset
751
kono
parents:
diff changeset
752 /* (src, dest, n) style memops. */
kono
parents:
diff changeset
753 case BUILT_IN_BCOPY:
kono
parents:
diff changeset
754 source0 = gimple_call_arg (call, 0);
kono
parents:
diff changeset
755 dest = gimple_call_arg (call, 1);
kono
parents:
diff changeset
756 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
757 break;
kono
parents:
diff changeset
758
kono
parents:
diff changeset
759 /* (dest, src, n) style memops. */
kono
parents:
diff changeset
760 case BUILT_IN_MEMCPY:
kono
parents:
diff changeset
761 case BUILT_IN_MEMCPY_CHK:
kono
parents:
diff changeset
762 case BUILT_IN_MEMMOVE:
kono
parents:
diff changeset
763 case BUILT_IN_MEMMOVE_CHK:
kono
parents:
diff changeset
764 case BUILT_IN_MEMPCPY:
kono
parents:
diff changeset
765 case BUILT_IN_MEMPCPY_CHK:
kono
parents:
diff changeset
766 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
767 source0 = gimple_call_arg (call, 1);
kono
parents:
diff changeset
768 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
769 break;
kono
parents:
diff changeset
770
kono
parents:
diff changeset
771 /* (dest, n) style memops. */
kono
parents:
diff changeset
772 case BUILT_IN_BZERO:
kono
parents:
diff changeset
773 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
774 len = gimple_call_arg (call, 1);
kono
parents:
diff changeset
775 break;
kono
parents:
diff changeset
776
kono
parents:
diff changeset
777 /* (dest, x, n) style memops*/
kono
parents:
diff changeset
778 case BUILT_IN_MEMSET:
kono
parents:
diff changeset
779 case BUILT_IN_MEMSET_CHK:
kono
parents:
diff changeset
780 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
781 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
782 break;
kono
parents:
diff changeset
783
kono
parents:
diff changeset
784 case BUILT_IN_STRLEN:
kono
parents:
diff changeset
785 source0 = gimple_call_arg (call, 0);
kono
parents:
diff changeset
786 len = gimple_call_lhs (call);
kono
parents:
diff changeset
787 break;
kono
parents:
diff changeset
788
kono
parents:
diff changeset
789 case BUILT_IN_STACK_RESTORE:
kono
parents:
diff changeset
790 handle_builtin_stack_restore (call, iter);
kono
parents:
diff changeset
791 break;
kono
parents:
diff changeset
792
kono
parents:
diff changeset
793 CASE_BUILT_IN_ALLOCA:
kono
parents:
diff changeset
794 handle_builtin_alloca (call, iter);
kono
parents:
diff changeset
795 break;
kono
parents:
diff changeset
796 /* And now the __atomic* and __sync builtins.
kono
parents:
diff changeset
797 These are handled differently from the classical memory memory
kono
parents:
diff changeset
798 access builtins above. */
kono
parents:
diff changeset
799
kono
parents:
diff changeset
800 case BUILT_IN_ATOMIC_LOAD_1:
kono
parents:
diff changeset
801 is_store = false;
kono
parents:
diff changeset
802 /* FALLTHRU */
kono
parents:
diff changeset
803 case BUILT_IN_SYNC_FETCH_AND_ADD_1:
kono
parents:
diff changeset
804 case BUILT_IN_SYNC_FETCH_AND_SUB_1:
kono
parents:
diff changeset
805 case BUILT_IN_SYNC_FETCH_AND_OR_1:
kono
parents:
diff changeset
806 case BUILT_IN_SYNC_FETCH_AND_AND_1:
kono
parents:
diff changeset
807 case BUILT_IN_SYNC_FETCH_AND_XOR_1:
kono
parents:
diff changeset
808 case BUILT_IN_SYNC_FETCH_AND_NAND_1:
kono
parents:
diff changeset
809 case BUILT_IN_SYNC_ADD_AND_FETCH_1:
kono
parents:
diff changeset
810 case BUILT_IN_SYNC_SUB_AND_FETCH_1:
kono
parents:
diff changeset
811 case BUILT_IN_SYNC_OR_AND_FETCH_1:
kono
parents:
diff changeset
812 case BUILT_IN_SYNC_AND_AND_FETCH_1:
kono
parents:
diff changeset
813 case BUILT_IN_SYNC_XOR_AND_FETCH_1:
kono
parents:
diff changeset
814 case BUILT_IN_SYNC_NAND_AND_FETCH_1:
kono
parents:
diff changeset
815 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
kono
parents:
diff changeset
816 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
kono
parents:
diff changeset
817 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
kono
parents:
diff changeset
818 case BUILT_IN_SYNC_LOCK_RELEASE_1:
kono
parents:
diff changeset
819 case BUILT_IN_ATOMIC_EXCHANGE_1:
kono
parents:
diff changeset
820 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
kono
parents:
diff changeset
821 case BUILT_IN_ATOMIC_STORE_1:
kono
parents:
diff changeset
822 case BUILT_IN_ATOMIC_ADD_FETCH_1:
kono
parents:
diff changeset
823 case BUILT_IN_ATOMIC_SUB_FETCH_1:
kono
parents:
diff changeset
824 case BUILT_IN_ATOMIC_AND_FETCH_1:
kono
parents:
diff changeset
825 case BUILT_IN_ATOMIC_NAND_FETCH_1:
kono
parents:
diff changeset
826 case BUILT_IN_ATOMIC_XOR_FETCH_1:
kono
parents:
diff changeset
827 case BUILT_IN_ATOMIC_OR_FETCH_1:
kono
parents:
diff changeset
828 case BUILT_IN_ATOMIC_FETCH_ADD_1:
kono
parents:
diff changeset
829 case BUILT_IN_ATOMIC_FETCH_SUB_1:
kono
parents:
diff changeset
830 case BUILT_IN_ATOMIC_FETCH_AND_1:
kono
parents:
diff changeset
831 case BUILT_IN_ATOMIC_FETCH_NAND_1:
kono
parents:
diff changeset
832 case BUILT_IN_ATOMIC_FETCH_XOR_1:
kono
parents:
diff changeset
833 case BUILT_IN_ATOMIC_FETCH_OR_1:
kono
parents:
diff changeset
834 access_size = 1;
kono
parents:
diff changeset
835 goto do_atomic;
kono
parents:
diff changeset
836
kono
parents:
diff changeset
837 case BUILT_IN_ATOMIC_LOAD_2:
kono
parents:
diff changeset
838 is_store = false;
kono
parents:
diff changeset
839 /* FALLTHRU */
kono
parents:
diff changeset
840 case BUILT_IN_SYNC_FETCH_AND_ADD_2:
kono
parents:
diff changeset
841 case BUILT_IN_SYNC_FETCH_AND_SUB_2:
kono
parents:
diff changeset
842 case BUILT_IN_SYNC_FETCH_AND_OR_2:
kono
parents:
diff changeset
843 case BUILT_IN_SYNC_FETCH_AND_AND_2:
kono
parents:
diff changeset
844 case BUILT_IN_SYNC_FETCH_AND_XOR_2:
kono
parents:
diff changeset
845 case BUILT_IN_SYNC_FETCH_AND_NAND_2:
kono
parents:
diff changeset
846 case BUILT_IN_SYNC_ADD_AND_FETCH_2:
kono
parents:
diff changeset
847 case BUILT_IN_SYNC_SUB_AND_FETCH_2:
kono
parents:
diff changeset
848 case BUILT_IN_SYNC_OR_AND_FETCH_2:
kono
parents:
diff changeset
849 case BUILT_IN_SYNC_AND_AND_FETCH_2:
kono
parents:
diff changeset
850 case BUILT_IN_SYNC_XOR_AND_FETCH_2:
kono
parents:
diff changeset
851 case BUILT_IN_SYNC_NAND_AND_FETCH_2:
kono
parents:
diff changeset
852 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
kono
parents:
diff changeset
853 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
kono
parents:
diff changeset
854 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
kono
parents:
diff changeset
855 case BUILT_IN_SYNC_LOCK_RELEASE_2:
kono
parents:
diff changeset
856 case BUILT_IN_ATOMIC_EXCHANGE_2:
kono
parents:
diff changeset
857 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
kono
parents:
diff changeset
858 case BUILT_IN_ATOMIC_STORE_2:
kono
parents:
diff changeset
859 case BUILT_IN_ATOMIC_ADD_FETCH_2:
kono
parents:
diff changeset
860 case BUILT_IN_ATOMIC_SUB_FETCH_2:
kono
parents:
diff changeset
861 case BUILT_IN_ATOMIC_AND_FETCH_2:
kono
parents:
diff changeset
862 case BUILT_IN_ATOMIC_NAND_FETCH_2:
kono
parents:
diff changeset
863 case BUILT_IN_ATOMIC_XOR_FETCH_2:
kono
parents:
diff changeset
864 case BUILT_IN_ATOMIC_OR_FETCH_2:
kono
parents:
diff changeset
865 case BUILT_IN_ATOMIC_FETCH_ADD_2:
kono
parents:
diff changeset
866 case BUILT_IN_ATOMIC_FETCH_SUB_2:
kono
parents:
diff changeset
867 case BUILT_IN_ATOMIC_FETCH_AND_2:
kono
parents:
diff changeset
868 case BUILT_IN_ATOMIC_FETCH_NAND_2:
kono
parents:
diff changeset
869 case BUILT_IN_ATOMIC_FETCH_XOR_2:
kono
parents:
diff changeset
870 case BUILT_IN_ATOMIC_FETCH_OR_2:
kono
parents:
diff changeset
871 access_size = 2;
kono
parents:
diff changeset
872 goto do_atomic;
kono
parents:
diff changeset
873
kono
parents:
diff changeset
874 case BUILT_IN_ATOMIC_LOAD_4:
kono
parents:
diff changeset
875 is_store = false;
kono
parents:
diff changeset
876 /* FALLTHRU */
kono
parents:
diff changeset
877 case BUILT_IN_SYNC_FETCH_AND_ADD_4:
kono
parents:
diff changeset
878 case BUILT_IN_SYNC_FETCH_AND_SUB_4:
kono
parents:
diff changeset
879 case BUILT_IN_SYNC_FETCH_AND_OR_4:
kono
parents:
diff changeset
880 case BUILT_IN_SYNC_FETCH_AND_AND_4:
kono
parents:
diff changeset
881 case BUILT_IN_SYNC_FETCH_AND_XOR_4:
kono
parents:
diff changeset
882 case BUILT_IN_SYNC_FETCH_AND_NAND_4:
kono
parents:
diff changeset
883 case BUILT_IN_SYNC_ADD_AND_FETCH_4:
kono
parents:
diff changeset
884 case BUILT_IN_SYNC_SUB_AND_FETCH_4:
kono
parents:
diff changeset
885 case BUILT_IN_SYNC_OR_AND_FETCH_4:
kono
parents:
diff changeset
886 case BUILT_IN_SYNC_AND_AND_FETCH_4:
kono
parents:
diff changeset
887 case BUILT_IN_SYNC_XOR_AND_FETCH_4:
kono
parents:
diff changeset
888 case BUILT_IN_SYNC_NAND_AND_FETCH_4:
kono
parents:
diff changeset
889 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
kono
parents:
diff changeset
890 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
kono
parents:
diff changeset
891 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
kono
parents:
diff changeset
892 case BUILT_IN_SYNC_LOCK_RELEASE_4:
kono
parents:
diff changeset
893 case BUILT_IN_ATOMIC_EXCHANGE_4:
kono
parents:
diff changeset
894 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
kono
parents:
diff changeset
895 case BUILT_IN_ATOMIC_STORE_4:
kono
parents:
diff changeset
896 case BUILT_IN_ATOMIC_ADD_FETCH_4:
kono
parents:
diff changeset
897 case BUILT_IN_ATOMIC_SUB_FETCH_4:
kono
parents:
diff changeset
898 case BUILT_IN_ATOMIC_AND_FETCH_4:
kono
parents:
diff changeset
899 case BUILT_IN_ATOMIC_NAND_FETCH_4:
kono
parents:
diff changeset
900 case BUILT_IN_ATOMIC_XOR_FETCH_4:
kono
parents:
diff changeset
901 case BUILT_IN_ATOMIC_OR_FETCH_4:
kono
parents:
diff changeset
902 case BUILT_IN_ATOMIC_FETCH_ADD_4:
kono
parents:
diff changeset
903 case BUILT_IN_ATOMIC_FETCH_SUB_4:
kono
parents:
diff changeset
904 case BUILT_IN_ATOMIC_FETCH_AND_4:
kono
parents:
diff changeset
905 case BUILT_IN_ATOMIC_FETCH_NAND_4:
kono
parents:
diff changeset
906 case BUILT_IN_ATOMIC_FETCH_XOR_4:
kono
parents:
diff changeset
907 case BUILT_IN_ATOMIC_FETCH_OR_4:
kono
parents:
diff changeset
908 access_size = 4;
kono
parents:
diff changeset
909 goto do_atomic;
kono
parents:
diff changeset
910
kono
parents:
diff changeset
911 case BUILT_IN_ATOMIC_LOAD_8:
kono
parents:
diff changeset
912 is_store = false;
kono
parents:
diff changeset
913 /* FALLTHRU */
kono
parents:
diff changeset
914 case BUILT_IN_SYNC_FETCH_AND_ADD_8:
kono
parents:
diff changeset
915 case BUILT_IN_SYNC_FETCH_AND_SUB_8:
kono
parents:
diff changeset
916 case BUILT_IN_SYNC_FETCH_AND_OR_8:
kono
parents:
diff changeset
917 case BUILT_IN_SYNC_FETCH_AND_AND_8:
kono
parents:
diff changeset
918 case BUILT_IN_SYNC_FETCH_AND_XOR_8:
kono
parents:
diff changeset
919 case BUILT_IN_SYNC_FETCH_AND_NAND_8:
kono
parents:
diff changeset
920 case BUILT_IN_SYNC_ADD_AND_FETCH_8:
kono
parents:
diff changeset
921 case BUILT_IN_SYNC_SUB_AND_FETCH_8:
kono
parents:
diff changeset
922 case BUILT_IN_SYNC_OR_AND_FETCH_8:
kono
parents:
diff changeset
923 case BUILT_IN_SYNC_AND_AND_FETCH_8:
kono
parents:
diff changeset
924 case BUILT_IN_SYNC_XOR_AND_FETCH_8:
kono
parents:
diff changeset
925 case BUILT_IN_SYNC_NAND_AND_FETCH_8:
kono
parents:
diff changeset
926 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
kono
parents:
diff changeset
927 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
kono
parents:
diff changeset
928 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
kono
parents:
diff changeset
929 case BUILT_IN_SYNC_LOCK_RELEASE_8:
kono
parents:
diff changeset
930 case BUILT_IN_ATOMIC_EXCHANGE_8:
kono
parents:
diff changeset
931 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
kono
parents:
diff changeset
932 case BUILT_IN_ATOMIC_STORE_8:
kono
parents:
diff changeset
933 case BUILT_IN_ATOMIC_ADD_FETCH_8:
kono
parents:
diff changeset
934 case BUILT_IN_ATOMIC_SUB_FETCH_8:
kono
parents:
diff changeset
935 case BUILT_IN_ATOMIC_AND_FETCH_8:
kono
parents:
diff changeset
936 case BUILT_IN_ATOMIC_NAND_FETCH_8:
kono
parents:
diff changeset
937 case BUILT_IN_ATOMIC_XOR_FETCH_8:
kono
parents:
diff changeset
938 case BUILT_IN_ATOMIC_OR_FETCH_8:
kono
parents:
diff changeset
939 case BUILT_IN_ATOMIC_FETCH_ADD_8:
kono
parents:
diff changeset
940 case BUILT_IN_ATOMIC_FETCH_SUB_8:
kono
parents:
diff changeset
941 case BUILT_IN_ATOMIC_FETCH_AND_8:
kono
parents:
diff changeset
942 case BUILT_IN_ATOMIC_FETCH_NAND_8:
kono
parents:
diff changeset
943 case BUILT_IN_ATOMIC_FETCH_XOR_8:
kono
parents:
diff changeset
944 case BUILT_IN_ATOMIC_FETCH_OR_8:
kono
parents:
diff changeset
945 access_size = 8;
kono
parents:
diff changeset
946 goto do_atomic;
kono
parents:
diff changeset
947
kono
parents:
diff changeset
948 case BUILT_IN_ATOMIC_LOAD_16:
kono
parents:
diff changeset
949 is_store = false;
kono
parents:
diff changeset
950 /* FALLTHRU */
kono
parents:
diff changeset
951 case BUILT_IN_SYNC_FETCH_AND_ADD_16:
kono
parents:
diff changeset
952 case BUILT_IN_SYNC_FETCH_AND_SUB_16:
kono
parents:
diff changeset
953 case BUILT_IN_SYNC_FETCH_AND_OR_16:
kono
parents:
diff changeset
954 case BUILT_IN_SYNC_FETCH_AND_AND_16:
kono
parents:
diff changeset
955 case BUILT_IN_SYNC_FETCH_AND_XOR_16:
kono
parents:
diff changeset
956 case BUILT_IN_SYNC_FETCH_AND_NAND_16:
kono
parents:
diff changeset
957 case BUILT_IN_SYNC_ADD_AND_FETCH_16:
kono
parents:
diff changeset
958 case BUILT_IN_SYNC_SUB_AND_FETCH_16:
kono
parents:
diff changeset
959 case BUILT_IN_SYNC_OR_AND_FETCH_16:
kono
parents:
diff changeset
960 case BUILT_IN_SYNC_AND_AND_FETCH_16:
kono
parents:
diff changeset
961 case BUILT_IN_SYNC_XOR_AND_FETCH_16:
kono
parents:
diff changeset
962 case BUILT_IN_SYNC_NAND_AND_FETCH_16:
kono
parents:
diff changeset
963 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
kono
parents:
diff changeset
964 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
kono
parents:
diff changeset
965 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
kono
parents:
diff changeset
966 case BUILT_IN_SYNC_LOCK_RELEASE_16:
kono
parents:
diff changeset
967 case BUILT_IN_ATOMIC_EXCHANGE_16:
kono
parents:
diff changeset
968 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
kono
parents:
diff changeset
969 case BUILT_IN_ATOMIC_STORE_16:
kono
parents:
diff changeset
970 case BUILT_IN_ATOMIC_ADD_FETCH_16:
kono
parents:
diff changeset
971 case BUILT_IN_ATOMIC_SUB_FETCH_16:
kono
parents:
diff changeset
972 case BUILT_IN_ATOMIC_AND_FETCH_16:
kono
parents:
diff changeset
973 case BUILT_IN_ATOMIC_NAND_FETCH_16:
kono
parents:
diff changeset
974 case BUILT_IN_ATOMIC_XOR_FETCH_16:
kono
parents:
diff changeset
975 case BUILT_IN_ATOMIC_OR_FETCH_16:
kono
parents:
diff changeset
976 case BUILT_IN_ATOMIC_FETCH_ADD_16:
kono
parents:
diff changeset
977 case BUILT_IN_ATOMIC_FETCH_SUB_16:
kono
parents:
diff changeset
978 case BUILT_IN_ATOMIC_FETCH_AND_16:
kono
parents:
diff changeset
979 case BUILT_IN_ATOMIC_FETCH_NAND_16:
kono
parents:
diff changeset
980 case BUILT_IN_ATOMIC_FETCH_XOR_16:
kono
parents:
diff changeset
981 case BUILT_IN_ATOMIC_FETCH_OR_16:
kono
parents:
diff changeset
982 access_size = 16;
kono
parents:
diff changeset
983 /* FALLTHRU */
kono
parents:
diff changeset
984 do_atomic:
kono
parents:
diff changeset
985 {
kono
parents:
diff changeset
986 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
987 /* DEST represents the address of a memory location.
kono
parents:
diff changeset
988 instrument_derefs wants the memory location, so lets
kono
parents:
diff changeset
989 dereference the address DEST before handing it to
kono
parents:
diff changeset
990 instrument_derefs. */
kono
parents:
diff changeset
991 tree type = build_nonstandard_integer_type (access_size
kono
parents:
diff changeset
992 * BITS_PER_UNIT, 1);
kono
parents:
diff changeset
993 dest = build2 (MEM_REF, type, dest,
kono
parents:
diff changeset
994 build_int_cst (build_pointer_type (char_type_node), 0));
kono
parents:
diff changeset
995 break;
kono
parents:
diff changeset
996 }
kono
parents:
diff changeset
997
kono
parents:
diff changeset
998 default:
kono
parents:
diff changeset
999 /* The other builtins memory access are not instrumented in this
kono
parents:
diff changeset
1000 function because they either don't have any length parameter,
kono
parents:
diff changeset
1001 or their length parameter is just a limit. */
kono
parents:
diff changeset
1002 break;
kono
parents:
diff changeset
1003 }
kono
parents:
diff changeset
1004
kono
parents:
diff changeset
1005 if (len != NULL_TREE)
kono
parents:
diff changeset
1006 {
kono
parents:
diff changeset
1007 if (source0 != NULL_TREE)
kono
parents:
diff changeset
1008 {
kono
parents:
diff changeset
1009 src0->start = source0;
kono
parents:
diff changeset
1010 src0->access_size = access_size;
kono
parents:
diff changeset
1011 *src0_len = len;
kono
parents:
diff changeset
1012 *src0_is_store = false;
kono
parents:
diff changeset
1013 }
kono
parents:
diff changeset
1014
kono
parents:
diff changeset
1015 if (source1 != NULL_TREE)
kono
parents:
diff changeset
1016 {
kono
parents:
diff changeset
1017 src1->start = source1;
kono
parents:
diff changeset
1018 src1->access_size = access_size;
kono
parents:
diff changeset
1019 *src1_len = len;
kono
parents:
diff changeset
1020 *src1_is_store = false;
kono
parents:
diff changeset
1021 }
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 if (dest != NULL_TREE)
kono
parents:
diff changeset
1024 {
kono
parents:
diff changeset
1025 dst->start = dest;
kono
parents:
diff changeset
1026 dst->access_size = access_size;
kono
parents:
diff changeset
1027 *dst_len = len;
kono
parents:
diff changeset
1028 *dst_is_store = true;
kono
parents:
diff changeset
1029 }
kono
parents:
diff changeset
1030
kono
parents:
diff changeset
1031 got_reference_p = true;
kono
parents:
diff changeset
1032 }
kono
parents:
diff changeset
1033 else if (dest)
kono
parents:
diff changeset
1034 {
kono
parents:
diff changeset
1035 dst->start = dest;
kono
parents:
diff changeset
1036 dst->access_size = access_size;
kono
parents:
diff changeset
1037 *dst_len = NULL_TREE;
kono
parents:
diff changeset
1038 *dst_is_store = is_store;
kono
parents:
diff changeset
1039 *dest_is_deref = true;
kono
parents:
diff changeset
1040 got_reference_p = true;
kono
parents:
diff changeset
1041 }
kono
parents:
diff changeset
1042
kono
parents:
diff changeset
1043 return got_reference_p;
kono
parents:
diff changeset
1044 }
kono
parents:
diff changeset
1045
kono
parents:
diff changeset
1046 /* Return true iff a given gimple statement has been instrumented.
kono
parents:
diff changeset
1047 Note that the statement is "defined" by the memory references it
kono
parents:
diff changeset
1048 contains. */
kono
parents:
diff changeset
1049
kono
parents:
diff changeset
1050 static bool
kono
parents:
diff changeset
1051 has_stmt_been_instrumented_p (gimple *stmt)
kono
parents:
diff changeset
1052 {
kono
parents:
diff changeset
1053 if (gimple_assign_single_p (stmt))
kono
parents:
diff changeset
1054 {
kono
parents:
diff changeset
1055 bool r_is_store;
kono
parents:
diff changeset
1056 asan_mem_ref r;
kono
parents:
diff changeset
1057 asan_mem_ref_init (&r, NULL, 1);
kono
parents:
diff changeset
1058
kono
parents:
diff changeset
1059 if (get_mem_ref_of_assignment (as_a <gassign *> (stmt), &r,
kono
parents:
diff changeset
1060 &r_is_store))
kono
parents:
diff changeset
1061 return has_mem_ref_been_instrumented (&r);
kono
parents:
diff changeset
1062 }
kono
parents:
diff changeset
1063 else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
kono
parents:
diff changeset
1064 {
kono
parents:
diff changeset
1065 asan_mem_ref src0, src1, dest;
kono
parents:
diff changeset
1066 asan_mem_ref_init (&src0, NULL, 1);
kono
parents:
diff changeset
1067 asan_mem_ref_init (&src1, NULL, 1);
kono
parents:
diff changeset
1068 asan_mem_ref_init (&dest, NULL, 1);
kono
parents:
diff changeset
1069
kono
parents:
diff changeset
1070 tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
kono
parents:
diff changeset
1071 bool src0_is_store = false, src1_is_store = false,
kono
parents:
diff changeset
1072 dest_is_store = false, dest_is_deref = false, intercepted_p = true;
kono
parents:
diff changeset
1073 if (get_mem_refs_of_builtin_call (as_a <gcall *> (stmt),
kono
parents:
diff changeset
1074 &src0, &src0_len, &src0_is_store,
kono
parents:
diff changeset
1075 &src1, &src1_len, &src1_is_store,
kono
parents:
diff changeset
1076 &dest, &dest_len, &dest_is_store,
kono
parents:
diff changeset
1077 &dest_is_deref, &intercepted_p))
kono
parents:
diff changeset
1078 {
kono
parents:
diff changeset
1079 if (src0.start != NULL_TREE
kono
parents:
diff changeset
1080 && !has_mem_ref_been_instrumented (&src0, src0_len))
kono
parents:
diff changeset
1081 return false;
kono
parents:
diff changeset
1082
kono
parents:
diff changeset
1083 if (src1.start != NULL_TREE
kono
parents:
diff changeset
1084 && !has_mem_ref_been_instrumented (&src1, src1_len))
kono
parents:
diff changeset
1085 return false;
kono
parents:
diff changeset
1086
kono
parents:
diff changeset
1087 if (dest.start != NULL_TREE
kono
parents:
diff changeset
1088 && !has_mem_ref_been_instrumented (&dest, dest_len))
kono
parents:
diff changeset
1089 return false;
kono
parents:
diff changeset
1090
kono
parents:
diff changeset
1091 return true;
kono
parents:
diff changeset
1092 }
kono
parents:
diff changeset
1093 }
kono
parents:
diff changeset
1094 else if (is_gimple_call (stmt) && gimple_store_p (stmt))
kono
parents:
diff changeset
1095 {
kono
parents:
diff changeset
1096 asan_mem_ref r;
kono
parents:
diff changeset
1097 asan_mem_ref_init (&r, NULL, 1);
kono
parents:
diff changeset
1098
kono
parents:
diff changeset
1099 r.start = gimple_call_lhs (stmt);
kono
parents:
diff changeset
1100 r.access_size = int_size_in_bytes (TREE_TYPE (r.start));
kono
parents:
diff changeset
1101 return has_mem_ref_been_instrumented (&r);
kono
parents:
diff changeset
1102 }
kono
parents:
diff changeset
1103
kono
parents:
diff changeset
1104 return false;
kono
parents:
diff changeset
1105 }
kono
parents:
diff changeset
1106
kono
parents:
diff changeset
1107 /* Insert a memory reference into the hash table. */
kono
parents:
diff changeset
1108
kono
parents:
diff changeset
1109 static void
kono
parents:
diff changeset
1110 update_mem_ref_hash_table (tree ref, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
1111 {
kono
parents:
diff changeset
1112 hash_table<asan_mem_ref_hasher> *ht = get_mem_ref_hash_table ();
kono
parents:
diff changeset
1113
kono
parents:
diff changeset
1114 asan_mem_ref r;
kono
parents:
diff changeset
1115 asan_mem_ref_init (&r, ref, access_size);
kono
parents:
diff changeset
1116
kono
parents:
diff changeset
1117 asan_mem_ref **slot = ht->find_slot (&r, INSERT);
kono
parents:
diff changeset
1118 if (*slot == NULL || (*slot)->access_size < access_size)
kono
parents:
diff changeset
1119 *slot = asan_mem_ref_new (ref, access_size);
kono
parents:
diff changeset
1120 }
kono
parents:
diff changeset
1121
kono
parents:
diff changeset
1122 /* Initialize shadow_ptr_types array. */
kono
parents:
diff changeset
1123
kono
parents:
diff changeset
1124 static void
kono
parents:
diff changeset
1125 asan_init_shadow_ptr_types (void)
kono
parents:
diff changeset
1126 {
kono
parents:
diff changeset
1127 asan_shadow_set = new_alias_set ();
kono
parents:
diff changeset
1128 tree types[3] = { signed_char_type_node, short_integer_type_node,
kono
parents:
diff changeset
1129 integer_type_node };
kono
parents:
diff changeset
1130
kono
parents:
diff changeset
1131 for (unsigned i = 0; i < 3; i++)
kono
parents:
diff changeset
1132 {
kono
parents:
diff changeset
1133 shadow_ptr_types[i] = build_distinct_type_copy (types[i]);
kono
parents:
diff changeset
1134 TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set;
kono
parents:
diff changeset
1135 shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]);
kono
parents:
diff changeset
1136 }
kono
parents:
diff changeset
1137
kono
parents:
diff changeset
1138 initialize_sanitizer_builtins ();
kono
parents:
diff changeset
1139 }
kono
parents:
diff changeset
1140
kono
parents:
diff changeset
1141 /* Create ADDR_EXPR of STRING_CST with the PP pretty printer text. */
kono
parents:
diff changeset
1142
kono
parents:
diff changeset
1143 static tree
kono
parents:
diff changeset
1144 asan_pp_string (pretty_printer *pp)
kono
parents:
diff changeset
1145 {
kono
parents:
diff changeset
1146 const char *buf = pp_formatted_text (pp);
kono
parents:
diff changeset
1147 size_t len = strlen (buf);
kono
parents:
diff changeset
1148 tree ret = build_string (len + 1, buf);
kono
parents:
diff changeset
1149 TREE_TYPE (ret)
kono
parents:
diff changeset
1150 = build_array_type (TREE_TYPE (shadow_ptr_types[0]),
kono
parents:
diff changeset
1151 build_index_type (size_int (len)));
kono
parents:
diff changeset
1152 TREE_READONLY (ret) = 1;
kono
parents:
diff changeset
1153 TREE_STATIC (ret) = 1;
kono
parents:
diff changeset
1154 return build1 (ADDR_EXPR, shadow_ptr_types[0], ret);
kono
parents:
diff changeset
1155 }
kono
parents:
diff changeset
1156
kono
parents:
diff changeset
1157 /* Clear shadow memory at SHADOW_MEM, LEN bytes. Can't call a library call here
kono
parents:
diff changeset
1158 though. */
kono
parents:
diff changeset
1159
kono
parents:
diff changeset
1160 static void
kono
parents:
diff changeset
1161 asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
kono
parents:
diff changeset
1162 {
kono
parents:
diff changeset
1163 rtx_insn *insn, *insns, *jump;
kono
parents:
diff changeset
1164 rtx_code_label *top_label;
kono
parents:
diff changeset
1165 rtx end, addr, tmp;
kono
parents:
diff changeset
1166
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1167 gcc_assert ((len & 3) == 0);
111
kono
parents:
diff changeset
1168 start_sequence ();
kono
parents:
diff changeset
1169 clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL);
kono
parents:
diff changeset
1170 insns = get_insns ();
kono
parents:
diff changeset
1171 end_sequence ();
kono
parents:
diff changeset
1172 for (insn = insns; insn; insn = NEXT_INSN (insn))
kono
parents:
diff changeset
1173 if (CALL_P (insn))
kono
parents:
diff changeset
1174 break;
kono
parents:
diff changeset
1175 if (insn == NULL_RTX)
kono
parents:
diff changeset
1176 {
kono
parents:
diff changeset
1177 emit_insn (insns);
kono
parents:
diff changeset
1178 return;
kono
parents:
diff changeset
1179 }
kono
parents:
diff changeset
1180
kono
parents:
diff changeset
1181 top_label = gen_label_rtx ();
kono
parents:
diff changeset
1182 addr = copy_to_mode_reg (Pmode, XEXP (shadow_mem, 0));
kono
parents:
diff changeset
1183 shadow_mem = adjust_automodify_address (shadow_mem, SImode, addr, 0);
kono
parents:
diff changeset
1184 end = force_reg (Pmode, plus_constant (Pmode, addr, len));
kono
parents:
diff changeset
1185 emit_label (top_label);
kono
parents:
diff changeset
1186
kono
parents:
diff changeset
1187 emit_move_insn (shadow_mem, const0_rtx);
kono
parents:
diff changeset
1188 tmp = expand_simple_binop (Pmode, PLUS, addr, gen_int_mode (4, Pmode), addr,
kono
parents:
diff changeset
1189 true, OPTAB_LIB_WIDEN);
kono
parents:
diff changeset
1190 if (tmp != addr)
kono
parents:
diff changeset
1191 emit_move_insn (addr, tmp);
kono
parents:
diff changeset
1192 emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label);
kono
parents:
diff changeset
1193 jump = get_last_insn ();
kono
parents:
diff changeset
1194 gcc_assert (JUMP_P (jump));
kono
parents:
diff changeset
1195 add_reg_br_prob_note (jump,
kono
parents:
diff changeset
1196 profile_probability::guessed_always ()
kono
parents:
diff changeset
1197 .apply_scale (80, 100));
kono
parents:
diff changeset
1198 }
kono
parents:
diff changeset
1199
kono
parents:
diff changeset
1200 void
kono
parents:
diff changeset
1201 asan_function_start (void)
kono
parents:
diff changeset
1202 {
kono
parents:
diff changeset
1203 section *fnsec = function_section (current_function_decl);
kono
parents:
diff changeset
1204 switch_to_section (fnsec);
kono
parents:
diff changeset
1205 ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LASANPC",
kono
parents:
diff changeset
1206 current_function_funcdef_no);
kono
parents:
diff changeset
1207 }
kono
parents:
diff changeset
1208
kono
parents:
diff changeset
1209 /* Return number of shadow bytes that are occupied by a local variable
kono
parents:
diff changeset
1210 of SIZE bytes. */
kono
parents:
diff changeset
1211
kono
parents:
diff changeset
1212 static unsigned HOST_WIDE_INT
kono
parents:
diff changeset
1213 shadow_mem_size (unsigned HOST_WIDE_INT size)
kono
parents:
diff changeset
1214 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1215 /* It must be possible to align stack variables to granularity
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1216 of shadow memory. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1217 gcc_assert (BITS_PER_UNIT
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1218 * ASAN_SHADOW_GRANULARITY <= MAX_SUPPORTED_STACK_ALIGNMENT);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1219
111
kono
parents:
diff changeset
1220 return ROUND_UP (size, ASAN_SHADOW_GRANULARITY) / ASAN_SHADOW_GRANULARITY;
kono
parents:
diff changeset
1221 }
kono
parents:
diff changeset
1222
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1223 /* Always emit 4 bytes at a time. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1224 #define RZ_BUFFER_SIZE 4
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1225
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1226 /* ASAN redzone buffer container that handles emission of shadow bytes. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1227 class asan_redzone_buffer
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1228 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1229 public:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1230 /* Constructor. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1231 asan_redzone_buffer (rtx shadow_mem, HOST_WIDE_INT prev_offset):
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1232 m_shadow_mem (shadow_mem), m_prev_offset (prev_offset),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1233 m_original_offset (prev_offset), m_shadow_bytes (RZ_BUFFER_SIZE)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1234 {}
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1235
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1236 /* Emit VALUE shadow byte at a given OFFSET. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1237 void emit_redzone_byte (HOST_WIDE_INT offset, unsigned char value);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1238
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1239 /* Emit RTX emission of the content of the buffer. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1240 void flush_redzone_payload (void);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1241
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1242 private:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1243 /* Flush if the content of the buffer is full
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1244 (equal to RZ_BUFFER_SIZE). */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1245 void flush_if_full (void);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1246
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1247 /* Memory where we last emitted a redzone payload. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1248 rtx m_shadow_mem;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1249
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1250 /* Relative offset where we last emitted a redzone payload. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1251 HOST_WIDE_INT m_prev_offset;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1252
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1253 /* Relative original offset. Used for checking only. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1254 HOST_WIDE_INT m_original_offset;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1255
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1256 public:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1257 /* Buffer with redzone payload. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1258 auto_vec<unsigned char> m_shadow_bytes;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1259 };
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1260
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1261 /* Emit VALUE shadow byte at a given OFFSET. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1262
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1263 void
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1264 asan_redzone_buffer::emit_redzone_byte (HOST_WIDE_INT offset,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1265 unsigned char value)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1266 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1267 gcc_assert ((offset & (ASAN_SHADOW_GRANULARITY - 1)) == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1268 gcc_assert (offset >= m_prev_offset);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1269
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1270 HOST_WIDE_INT off
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1271 = m_prev_offset + ASAN_SHADOW_GRANULARITY * m_shadow_bytes.length ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1272 if (off == offset)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1273 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1274 /* Consecutive shadow memory byte. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1275 m_shadow_bytes.safe_push (value);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1276 flush_if_full ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1277 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1278 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1279 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1280 if (!m_shadow_bytes.is_empty ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1281 flush_redzone_payload ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1282
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1283 /* Maybe start earlier in order to use aligned store. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1284 HOST_WIDE_INT align = (offset - m_prev_offset) % ASAN_RED_ZONE_SIZE;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1285 if (align)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1286 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1287 offset -= align;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1288 for (unsigned i = 0; i < align / BITS_PER_UNIT; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1289 m_shadow_bytes.safe_push (0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1290 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1291
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1292 /* Adjust m_prev_offset and m_shadow_mem. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1293 HOST_WIDE_INT diff = offset - m_prev_offset;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1294 m_shadow_mem = adjust_address (m_shadow_mem, VOIDmode,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1295 diff >> ASAN_SHADOW_SHIFT);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1296 m_prev_offset = offset;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1297 m_shadow_bytes.safe_push (value);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1298 flush_if_full ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1299 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1300 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1301
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1302 /* Emit RTX emission of the content of the buffer. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1303
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1304 void
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1305 asan_redzone_buffer::flush_redzone_payload (void)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1306 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1307 gcc_assert (WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1308
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1309 if (m_shadow_bytes.is_empty ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1310 return;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1311
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1312 /* Be sure we always emit to an aligned address. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1313 gcc_assert (((m_prev_offset - m_original_offset)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1314 & (ASAN_RED_ZONE_SIZE - 1)) == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1315
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1316 /* Fill it to RZ_BUFFER_SIZE bytes with zeros if needed. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1317 unsigned l = m_shadow_bytes.length ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1318 for (unsigned i = 0; i <= RZ_BUFFER_SIZE - l; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1319 m_shadow_bytes.safe_push (0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1320
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1321 if (dump_file && (dump_flags & TDF_DETAILS))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1322 fprintf (dump_file,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1323 "Flushing rzbuffer at offset %" PRId64 " with: ", m_prev_offset);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1324
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1325 unsigned HOST_WIDE_INT val = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1326 for (unsigned i = 0; i < RZ_BUFFER_SIZE; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1327 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1328 unsigned char v
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1329 = m_shadow_bytes[BYTES_BIG_ENDIAN ? RZ_BUFFER_SIZE - i - 1 : i];
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1330 val |= (unsigned HOST_WIDE_INT)v << (BITS_PER_UNIT * i);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1331 if (dump_file && (dump_flags & TDF_DETAILS))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1332 fprintf (dump_file, "%02x ", v);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1333 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1334
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1335 if (dump_file && (dump_flags & TDF_DETAILS))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1336 fprintf (dump_file, "\n");
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1337
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1338 rtx c = gen_int_mode (val, SImode);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1339 m_shadow_mem = adjust_address (m_shadow_mem, SImode, 0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1340 emit_move_insn (m_shadow_mem, c);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1341 m_shadow_bytes.truncate (0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1342 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1343
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1344 /* Flush if the content of the buffer is full
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1345 (equal to RZ_BUFFER_SIZE). */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1346
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1347 void
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1348 asan_redzone_buffer::flush_if_full (void)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1349 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1350 if (m_shadow_bytes.length () == RZ_BUFFER_SIZE)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1351 flush_redzone_payload ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1352 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1353
111
kono
parents:
diff changeset
1354 /* Insert code to protect stack vars. The prologue sequence should be emitted
kono
parents:
diff changeset
1355 directly, epilogue sequence returned. BASE is the register holding the
kono
parents:
diff changeset
1356 stack base, against which OFFSETS array offsets are relative to, OFFSETS
kono
parents:
diff changeset
1357 array contains pairs of offsets in reverse order, always the end offset
kono
parents:
diff changeset
1358 of some gap that needs protection followed by starting offset,
kono
parents:
diff changeset
1359 and DECLS is an array of representative decls for each var partition.
kono
parents:
diff changeset
1360 LENGTH is the length of the OFFSETS array, DECLS array is LENGTH / 2 - 1
kono
parents:
diff changeset
1361 elements long (OFFSETS include gap before the first variable as well
kono
parents:
diff changeset
1362 as gaps after each stack variable). PBASE is, if non-NULL, some pseudo
kono
parents:
diff changeset
1363 register which stack vars DECL_RTLs are based on. Either BASE should be
kono
parents:
diff changeset
1364 assigned to PBASE, when not doing use after return protection, or
kono
parents:
diff changeset
1365 corresponding address based on __asan_stack_malloc* return value. */
kono
parents:
diff changeset
1366
kono
parents:
diff changeset
1367 rtx_insn *
kono
parents:
diff changeset
1368 asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
kono
parents:
diff changeset
1369 HOST_WIDE_INT *offsets, tree *decls, int length)
kono
parents:
diff changeset
1370 {
kono
parents:
diff changeset
1371 rtx shadow_base, shadow_mem, ret, mem, orig_base;
kono
parents:
diff changeset
1372 rtx_code_label *lab;
kono
parents:
diff changeset
1373 rtx_insn *insns;
kono
parents:
diff changeset
1374 char buf[32];
kono
parents:
diff changeset
1375 HOST_WIDE_INT base_offset = offsets[length - 1];
kono
parents:
diff changeset
1376 HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
kono
parents:
diff changeset
1377 HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1378 HOST_WIDE_INT last_offset, last_size, last_size_aligned;
111
kono
parents:
diff changeset
1379 int l;
kono
parents:
diff changeset
1380 unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
kono
parents:
diff changeset
1381 tree str_cst, decl, id;
kono
parents:
diff changeset
1382 int use_after_return_class = -1;
kono
parents:
diff changeset
1383
kono
parents:
diff changeset
1384 if (shadow_ptr_types[0] == NULL_TREE)
kono
parents:
diff changeset
1385 asan_init_shadow_ptr_types ();
kono
parents:
diff changeset
1386
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1387 expanded_location cfun_xloc
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1388 = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1389
111
kono
parents:
diff changeset
1390 /* First of all, prepare the description string. */
kono
parents:
diff changeset
1391 pretty_printer asan_pp;
kono
parents:
diff changeset
1392
kono
parents:
diff changeset
1393 pp_decimal_int (&asan_pp, length / 2 - 1);
kono
parents:
diff changeset
1394 pp_space (&asan_pp);
kono
parents:
diff changeset
1395 for (l = length - 2; l; l -= 2)
kono
parents:
diff changeset
1396 {
kono
parents:
diff changeset
1397 tree decl = decls[l / 2 - 1];
kono
parents:
diff changeset
1398 pp_wide_integer (&asan_pp, offsets[l] - base_offset);
kono
parents:
diff changeset
1399 pp_space (&asan_pp);
kono
parents:
diff changeset
1400 pp_wide_integer (&asan_pp, offsets[l - 1] - offsets[l]);
kono
parents:
diff changeset
1401 pp_space (&asan_pp);
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1402
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1403 expanded_location xloc
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1404 = expand_location (DECL_SOURCE_LOCATION (decl));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1405 char location[32];
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1406
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1407 if (xloc.file == cfun_xloc.file)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1408 sprintf (location, ":%d", xloc.line);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1409 else
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1410 location[0] = '\0';
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1411
111
kono
parents:
diff changeset
1412 if (DECL_P (decl) && DECL_NAME (decl))
kono
parents:
diff changeset
1413 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1414 unsigned idlen
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1415 = IDENTIFIER_LENGTH (DECL_NAME (decl)) + strlen (location);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1416 pp_decimal_int (&asan_pp, idlen);
111
kono
parents:
diff changeset
1417 pp_space (&asan_pp);
kono
parents:
diff changeset
1418 pp_tree_identifier (&asan_pp, DECL_NAME (decl));
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1419 pp_string (&asan_pp, location);
111
kono
parents:
diff changeset
1420 }
kono
parents:
diff changeset
1421 else
kono
parents:
diff changeset
1422 pp_string (&asan_pp, "9 <unknown>");
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1423
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1424 if (l > 2)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1425 pp_space (&asan_pp);
111
kono
parents:
diff changeset
1426 }
kono
parents:
diff changeset
1427 str_cst = asan_pp_string (&asan_pp);
kono
parents:
diff changeset
1428
kono
parents:
diff changeset
1429 /* Emit the prologue sequence. */
kono
parents:
diff changeset
1430 if (asan_frame_size > 32 && asan_frame_size <= 65536 && pbase
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1431 && param_asan_use_after_return)
111
kono
parents:
diff changeset
1432 {
kono
parents:
diff changeset
1433 use_after_return_class = floor_log2 (asan_frame_size - 1) - 5;
kono
parents:
diff changeset
1434 /* __asan_stack_malloc_N guarantees alignment
kono
parents:
diff changeset
1435 N < 6 ? (64 << N) : 4096 bytes. */
kono
parents:
diff changeset
1436 if (alignb > (use_after_return_class < 6
kono
parents:
diff changeset
1437 ? (64U << use_after_return_class) : 4096U))
kono
parents:
diff changeset
1438 use_after_return_class = -1;
kono
parents:
diff changeset
1439 else if (alignb > ASAN_RED_ZONE_SIZE && (asan_frame_size & (alignb - 1)))
kono
parents:
diff changeset
1440 base_align_bias = ((asan_frame_size + alignb - 1)
kono
parents:
diff changeset
1441 & ~(alignb - HOST_WIDE_INT_1)) - asan_frame_size;
kono
parents:
diff changeset
1442 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1443
111
kono
parents:
diff changeset
1444 /* Align base if target is STRICT_ALIGNMENT. */
kono
parents:
diff changeset
1445 if (STRICT_ALIGNMENT)
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1446 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1447 const HOST_WIDE_INT align
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1448 = (GET_MODE_ALIGNMENT (SImode) / BITS_PER_UNIT) << ASAN_SHADOW_SHIFT;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1449 base = expand_binop (Pmode, and_optab, base, gen_int_mode (-align, Pmode),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1450 NULL_RTX, 1, OPTAB_DIRECT);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1451 }
111
kono
parents:
diff changeset
1452
kono
parents:
diff changeset
1453 if (use_after_return_class == -1 && pbase)
kono
parents:
diff changeset
1454 emit_move_insn (pbase, base);
kono
parents:
diff changeset
1455
kono
parents:
diff changeset
1456 base = expand_binop (Pmode, add_optab, base,
kono
parents:
diff changeset
1457 gen_int_mode (base_offset - base_align_bias, Pmode),
kono
parents:
diff changeset
1458 NULL_RTX, 1, OPTAB_DIRECT);
kono
parents:
diff changeset
1459 orig_base = NULL_RTX;
kono
parents:
diff changeset
1460 if (use_after_return_class != -1)
kono
parents:
diff changeset
1461 {
kono
parents:
diff changeset
1462 if (asan_detect_stack_use_after_return == NULL_TREE)
kono
parents:
diff changeset
1463 {
kono
parents:
diff changeset
1464 id = get_identifier ("__asan_option_detect_stack_use_after_return");
kono
parents:
diff changeset
1465 decl = build_decl (BUILTINS_LOCATION, VAR_DECL, id,
kono
parents:
diff changeset
1466 integer_type_node);
kono
parents:
diff changeset
1467 SET_DECL_ASSEMBLER_NAME (decl, id);
kono
parents:
diff changeset
1468 TREE_ADDRESSABLE (decl) = 1;
kono
parents:
diff changeset
1469 DECL_ARTIFICIAL (decl) = 1;
kono
parents:
diff changeset
1470 DECL_IGNORED_P (decl) = 1;
kono
parents:
diff changeset
1471 DECL_EXTERNAL (decl) = 1;
kono
parents:
diff changeset
1472 TREE_STATIC (decl) = 1;
kono
parents:
diff changeset
1473 TREE_PUBLIC (decl) = 1;
kono
parents:
diff changeset
1474 TREE_USED (decl) = 1;
kono
parents:
diff changeset
1475 asan_detect_stack_use_after_return = decl;
kono
parents:
diff changeset
1476 }
kono
parents:
diff changeset
1477 orig_base = gen_reg_rtx (Pmode);
kono
parents:
diff changeset
1478 emit_move_insn (orig_base, base);
kono
parents:
diff changeset
1479 ret = expand_normal (asan_detect_stack_use_after_return);
kono
parents:
diff changeset
1480 lab = gen_label_rtx ();
kono
parents:
diff changeset
1481 emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
kono
parents:
diff changeset
1482 VOIDmode, 0, lab,
kono
parents:
diff changeset
1483 profile_probability::very_likely ());
kono
parents:
diff changeset
1484 snprintf (buf, sizeof buf, "__asan_stack_malloc_%d",
kono
parents:
diff changeset
1485 use_after_return_class);
kono
parents:
diff changeset
1486 ret = init_one_libfunc (buf);
kono
parents:
diff changeset
1487 ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
kono
parents:
diff changeset
1488 GEN_INT (asan_frame_size
kono
parents:
diff changeset
1489 + base_align_bias),
kono
parents:
diff changeset
1490 TYPE_MODE (pointer_sized_int_node));
kono
parents:
diff changeset
1491 /* __asan_stack_malloc_[n] returns a pointer to fake stack if succeeded
kono
parents:
diff changeset
1492 and NULL otherwise. Check RET value is NULL here and jump over the
kono
parents:
diff changeset
1493 BASE reassignment in this case. Otherwise, reassign BASE to RET. */
kono
parents:
diff changeset
1494 emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
kono
parents:
diff changeset
1495 VOIDmode, 0, lab,
kono
parents:
diff changeset
1496 profile_probability:: very_unlikely ());
kono
parents:
diff changeset
1497 ret = convert_memory_address (Pmode, ret);
kono
parents:
diff changeset
1498 emit_move_insn (base, ret);
kono
parents:
diff changeset
1499 emit_label (lab);
kono
parents:
diff changeset
1500 emit_move_insn (pbase, expand_binop (Pmode, add_optab, base,
kono
parents:
diff changeset
1501 gen_int_mode (base_align_bias
kono
parents:
diff changeset
1502 - base_offset, Pmode),
kono
parents:
diff changeset
1503 NULL_RTX, 1, OPTAB_DIRECT));
kono
parents:
diff changeset
1504 }
kono
parents:
diff changeset
1505 mem = gen_rtx_MEM (ptr_mode, base);
kono
parents:
diff changeset
1506 mem = adjust_address (mem, VOIDmode, base_align_bias);
kono
parents:
diff changeset
1507 emit_move_insn (mem, gen_int_mode (ASAN_STACK_FRAME_MAGIC, ptr_mode));
kono
parents:
diff changeset
1508 mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
kono
parents:
diff changeset
1509 emit_move_insn (mem, expand_normal (str_cst));
kono
parents:
diff changeset
1510 mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
kono
parents:
diff changeset
1511 ASM_GENERATE_INTERNAL_LABEL (buf, "LASANPC", current_function_funcdef_no);
kono
parents:
diff changeset
1512 id = get_identifier (buf);
kono
parents:
diff changeset
1513 decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
kono
parents:
diff changeset
1514 VAR_DECL, id, char_type_node);
kono
parents:
diff changeset
1515 SET_DECL_ASSEMBLER_NAME (decl, id);
kono
parents:
diff changeset
1516 TREE_ADDRESSABLE (decl) = 1;
kono
parents:
diff changeset
1517 TREE_READONLY (decl) = 1;
kono
parents:
diff changeset
1518 DECL_ARTIFICIAL (decl) = 1;
kono
parents:
diff changeset
1519 DECL_IGNORED_P (decl) = 1;
kono
parents:
diff changeset
1520 TREE_STATIC (decl) = 1;
kono
parents:
diff changeset
1521 TREE_PUBLIC (decl) = 0;
kono
parents:
diff changeset
1522 TREE_USED (decl) = 1;
kono
parents:
diff changeset
1523 DECL_INITIAL (decl) = decl;
kono
parents:
diff changeset
1524 TREE_ASM_WRITTEN (decl) = 1;
kono
parents:
diff changeset
1525 TREE_ASM_WRITTEN (id) = 1;
kono
parents:
diff changeset
1526 emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl)));
kono
parents:
diff changeset
1527 shadow_base = expand_binop (Pmode, lshr_optab, base,
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1528 gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT),
111
kono
parents:
diff changeset
1529 NULL_RTX, 1, OPTAB_DIRECT);
kono
parents:
diff changeset
1530 shadow_base
kono
parents:
diff changeset
1531 = plus_constant (Pmode, shadow_base,
kono
parents:
diff changeset
1532 asan_shadow_offset ()
kono
parents:
diff changeset
1533 + (base_align_bias >> ASAN_SHADOW_SHIFT));
kono
parents:
diff changeset
1534 gcc_assert (asan_shadow_set != -1
kono
parents:
diff changeset
1535 && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
kono
parents:
diff changeset
1536 shadow_mem = gen_rtx_MEM (SImode, shadow_base);
kono
parents:
diff changeset
1537 set_mem_alias_set (shadow_mem, asan_shadow_set);
kono
parents:
diff changeset
1538 if (STRICT_ALIGNMENT)
kono
parents:
diff changeset
1539 set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
kono
parents:
diff changeset
1540 prev_offset = base_offset;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1541
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1542 asan_redzone_buffer rz_buffer (shadow_mem, prev_offset);
111
kono
parents:
diff changeset
1543 for (l = length; l; l -= 2)
kono
parents:
diff changeset
1544 {
kono
parents:
diff changeset
1545 if (l == 2)
kono
parents:
diff changeset
1546 cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT;
kono
parents:
diff changeset
1547 offset = offsets[l - 1];
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1548
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1549 bool extra_byte = (offset - base_offset) & (ASAN_SHADOW_GRANULARITY - 1);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1550 /* If a red-zone is not aligned to ASAN_SHADOW_GRANULARITY then
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1551 the previous stack variable has size % ASAN_SHADOW_GRANULARITY != 0.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1552 In that case we have to emit one extra byte that will describe
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1553 how many bytes (our of ASAN_SHADOW_GRANULARITY) can be accessed. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1554 if (extra_byte)
111
kono
parents:
diff changeset
1555 {
kono
parents:
diff changeset
1556 HOST_WIDE_INT aoff
kono
parents:
diff changeset
1557 = base_offset + ((offset - base_offset)
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1558 & ~(ASAN_SHADOW_GRANULARITY - HOST_WIDE_INT_1));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1559 rz_buffer.emit_redzone_byte (aoff, offset - aoff);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1560 offset = aoff + ASAN_SHADOW_GRANULARITY;
111
kono
parents:
diff changeset
1561 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1562
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1563 /* Calculate size of red zone payload. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1564 while (offset < offsets[l - 2])
111
kono
parents:
diff changeset
1565 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1566 rz_buffer.emit_redzone_byte (offset, cur_shadow_byte);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1567 offset += ASAN_SHADOW_GRANULARITY;
111
kono
parents:
diff changeset
1568 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1569
111
kono
parents:
diff changeset
1570 cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE;
kono
parents:
diff changeset
1571 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1572
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1573 /* As the automatic variables are aligned to
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1574 ASAN_RED_ZONE_SIZE / ASAN_SHADOW_GRANULARITY, the buffer should be
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1575 flushed here. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1576 gcc_assert (rz_buffer.m_shadow_bytes.is_empty ());
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1577
111
kono
parents:
diff changeset
1578 do_pending_stack_adjust ();
kono
parents:
diff changeset
1579
kono
parents:
diff changeset
1580 /* Construct epilogue sequence. */
kono
parents:
diff changeset
1581 start_sequence ();
kono
parents:
diff changeset
1582
kono
parents:
diff changeset
1583 lab = NULL;
kono
parents:
diff changeset
1584 if (use_after_return_class != -1)
kono
parents:
diff changeset
1585 {
kono
parents:
diff changeset
1586 rtx_code_label *lab2 = gen_label_rtx ();
kono
parents:
diff changeset
1587 char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
kono
parents:
diff changeset
1588 emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
kono
parents:
diff changeset
1589 VOIDmode, 0, lab2,
kono
parents:
diff changeset
1590 profile_probability::very_likely ());
kono
parents:
diff changeset
1591 shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
kono
parents:
diff changeset
1592 set_mem_alias_set (shadow_mem, asan_shadow_set);
kono
parents:
diff changeset
1593 mem = gen_rtx_MEM (ptr_mode, base);
kono
parents:
diff changeset
1594 mem = adjust_address (mem, VOIDmode, base_align_bias);
kono
parents:
diff changeset
1595 emit_move_insn (mem, gen_int_mode (ASAN_STACK_RETIRED_MAGIC, ptr_mode));
kono
parents:
diff changeset
1596 unsigned HOST_WIDE_INT sz = asan_frame_size >> ASAN_SHADOW_SHIFT;
kono
parents:
diff changeset
1597 if (use_after_return_class < 5
kono
parents:
diff changeset
1598 && can_store_by_pieces (sz, builtin_memset_read_str, &c,
kono
parents:
diff changeset
1599 BITS_PER_UNIT, true))
kono
parents:
diff changeset
1600 store_by_pieces (shadow_mem, sz, builtin_memset_read_str, &c,
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1601 BITS_PER_UNIT, true, RETURN_BEGIN);
111
kono
parents:
diff changeset
1602 else if (use_after_return_class >= 5
kono
parents:
diff changeset
1603 || !set_storage_via_setmem (shadow_mem,
kono
parents:
diff changeset
1604 GEN_INT (sz),
kono
parents:
diff changeset
1605 gen_int_mode (c, QImode),
kono
parents:
diff changeset
1606 BITS_PER_UNIT, BITS_PER_UNIT,
kono
parents:
diff changeset
1607 -1, sz, sz, sz))
kono
parents:
diff changeset
1608 {
kono
parents:
diff changeset
1609 snprintf (buf, sizeof buf, "__asan_stack_free_%d",
kono
parents:
diff changeset
1610 use_after_return_class);
kono
parents:
diff changeset
1611 ret = init_one_libfunc (buf);
kono
parents:
diff changeset
1612 rtx addr = convert_memory_address (ptr_mode, base);
kono
parents:
diff changeset
1613 rtx orig_addr = convert_memory_address (ptr_mode, orig_base);
kono
parents:
diff changeset
1614 emit_library_call (ret, LCT_NORMAL, ptr_mode, addr, ptr_mode,
kono
parents:
diff changeset
1615 GEN_INT (asan_frame_size + base_align_bias),
kono
parents:
diff changeset
1616 TYPE_MODE (pointer_sized_int_node),
kono
parents:
diff changeset
1617 orig_addr, ptr_mode);
kono
parents:
diff changeset
1618 }
kono
parents:
diff changeset
1619 lab = gen_label_rtx ();
kono
parents:
diff changeset
1620 emit_jump (lab);
kono
parents:
diff changeset
1621 emit_label (lab2);
kono
parents:
diff changeset
1622 }
kono
parents:
diff changeset
1623
kono
parents:
diff changeset
1624 shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
kono
parents:
diff changeset
1625 set_mem_alias_set (shadow_mem, asan_shadow_set);
kono
parents:
diff changeset
1626
kono
parents:
diff changeset
1627 if (STRICT_ALIGNMENT)
kono
parents:
diff changeset
1628 set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
kono
parents:
diff changeset
1629
kono
parents:
diff changeset
1630 prev_offset = base_offset;
kono
parents:
diff changeset
1631 last_offset = base_offset;
kono
parents:
diff changeset
1632 last_size = 0;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1633 last_size_aligned = 0;
111
kono
parents:
diff changeset
1634 for (l = length; l; l -= 2)
kono
parents:
diff changeset
1635 {
kono
parents:
diff changeset
1636 offset = base_offset + ((offsets[l - 1] - base_offset)
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1637 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1638 if (last_offset + last_size_aligned < offset)
111
kono
parents:
diff changeset
1639 {
kono
parents:
diff changeset
1640 shadow_mem = adjust_address (shadow_mem, VOIDmode,
kono
parents:
diff changeset
1641 (last_offset - prev_offset)
kono
parents:
diff changeset
1642 >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1643 prev_offset = last_offset;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1644 asan_clear_shadow (shadow_mem, last_size_aligned >> ASAN_SHADOW_SHIFT);
111
kono
parents:
diff changeset
1645 last_offset = offset;
kono
parents:
diff changeset
1646 last_size = 0;
kono
parents:
diff changeset
1647 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1648 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1649 last_size = offset - last_offset;
111
kono
parents:
diff changeset
1650 last_size += base_offset + ((offsets[l - 2] - base_offset)
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1651 & ~(ASAN_MIN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
111
kono
parents:
diff changeset
1652 - offset;
kono
parents:
diff changeset
1653
kono
parents:
diff changeset
1654 /* Unpoison shadow memory that corresponds to a variable that is
kono
parents:
diff changeset
1655 is subject of use-after-return sanitization. */
kono
parents:
diff changeset
1656 if (l > 2)
kono
parents:
diff changeset
1657 {
kono
parents:
diff changeset
1658 decl = decls[l / 2 - 2];
kono
parents:
diff changeset
1659 if (asan_handled_variables != NULL
kono
parents:
diff changeset
1660 && asan_handled_variables->contains (decl))
kono
parents:
diff changeset
1661 {
kono
parents:
diff changeset
1662 HOST_WIDE_INT size = offsets[l - 3] - offsets[l - 2];
kono
parents:
diff changeset
1663 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
1664 {
kono
parents:
diff changeset
1665 const char *n = (DECL_NAME (decl)
kono
parents:
diff changeset
1666 ? IDENTIFIER_POINTER (DECL_NAME (decl))
kono
parents:
diff changeset
1667 : "<unknown>");
kono
parents:
diff changeset
1668 fprintf (dump_file, "Unpoisoning shadow stack for variable: "
kono
parents:
diff changeset
1669 "%s (%" PRId64 " B)\n", n, size);
kono
parents:
diff changeset
1670 }
kono
parents:
diff changeset
1671
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1672 last_size += size & ~(ASAN_MIN_RED_ZONE_SIZE - HOST_WIDE_INT_1);
111
kono
parents:
diff changeset
1673 }
kono
parents:
diff changeset
1674 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1675 last_size_aligned
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1676 = ((last_size + (ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1677 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
111
kono
parents:
diff changeset
1678 }
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1679 if (last_size_aligned)
111
kono
parents:
diff changeset
1680 {
kono
parents:
diff changeset
1681 shadow_mem = adjust_address (shadow_mem, VOIDmode,
kono
parents:
diff changeset
1682 (last_offset - prev_offset)
kono
parents:
diff changeset
1683 >> ASAN_SHADOW_SHIFT);
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1684 asan_clear_shadow (shadow_mem, last_size_aligned >> ASAN_SHADOW_SHIFT);
111
kono
parents:
diff changeset
1685 }
kono
parents:
diff changeset
1686
kono
parents:
diff changeset
1687 /* Clean-up set with instrumented stack variables. */
kono
parents:
diff changeset
1688 delete asan_handled_variables;
kono
parents:
diff changeset
1689 asan_handled_variables = NULL;
kono
parents:
diff changeset
1690 delete asan_used_labels;
kono
parents:
diff changeset
1691 asan_used_labels = NULL;
kono
parents:
diff changeset
1692
kono
parents:
diff changeset
1693 do_pending_stack_adjust ();
kono
parents:
diff changeset
1694 if (lab)
kono
parents:
diff changeset
1695 emit_label (lab);
kono
parents:
diff changeset
1696
kono
parents:
diff changeset
1697 insns = get_insns ();
kono
parents:
diff changeset
1698 end_sequence ();
kono
parents:
diff changeset
1699 return insns;
kono
parents:
diff changeset
1700 }
kono
parents:
diff changeset
1701
kono
parents:
diff changeset
1702 /* Emit __asan_allocas_unpoison (top, bot) call. The BASE parameter corresponds
kono
parents:
diff changeset
1703 to BOT argument, for TOP virtual_stack_dynamic_rtx is used. NEW_SEQUENCE
kono
parents:
diff changeset
1704 indicates whether we're emitting new instructions sequence or not. */
kono
parents:
diff changeset
1705
kono
parents:
diff changeset
1706 rtx_insn *
kono
parents:
diff changeset
1707 asan_emit_allocas_unpoison (rtx top, rtx bot, rtx_insn *before)
kono
parents:
diff changeset
1708 {
kono
parents:
diff changeset
1709 if (before)
kono
parents:
diff changeset
1710 push_to_sequence (before);
kono
parents:
diff changeset
1711 else
kono
parents:
diff changeset
1712 start_sequence ();
kono
parents:
diff changeset
1713 rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
kono
parents:
diff changeset
1714 top = convert_memory_address (ptr_mode, top);
kono
parents:
diff changeset
1715 bot = convert_memory_address (ptr_mode, bot);
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1716 emit_library_call (ret, LCT_NORMAL, ptr_mode,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1717 top, ptr_mode, bot, ptr_mode);
111
kono
parents:
diff changeset
1718
kono
parents:
diff changeset
1719 do_pending_stack_adjust ();
kono
parents:
diff changeset
1720 rtx_insn *insns = get_insns ();
kono
parents:
diff changeset
1721 end_sequence ();
kono
parents:
diff changeset
1722 return insns;
kono
parents:
diff changeset
1723 }
kono
parents:
diff changeset
1724
kono
parents:
diff changeset
1725 /* Return true if DECL, a global var, might be overridden and needs
kono
parents:
diff changeset
1726 therefore a local alias. */
kono
parents:
diff changeset
1727
kono
parents:
diff changeset
1728 static bool
kono
parents:
diff changeset
1729 asan_needs_local_alias (tree decl)
kono
parents:
diff changeset
1730 {
kono
parents:
diff changeset
1731 return DECL_WEAK (decl) || !targetm.binds_local_p (decl);
kono
parents:
diff changeset
1732 }
kono
parents:
diff changeset
1733
kono
parents:
diff changeset
1734 /* Return true if DECL, a global var, is an artificial ODR indicator symbol
kono
parents:
diff changeset
1735 therefore doesn't need protection. */
kono
parents:
diff changeset
1736
kono
parents:
diff changeset
1737 static bool
kono
parents:
diff changeset
1738 is_odr_indicator (tree decl)
kono
parents:
diff changeset
1739 {
kono
parents:
diff changeset
1740 return (DECL_ARTIFICIAL (decl)
kono
parents:
diff changeset
1741 && lookup_attribute ("asan odr indicator", DECL_ATTRIBUTES (decl)));
kono
parents:
diff changeset
1742 }
kono
parents:
diff changeset
1743
kono
parents:
diff changeset
1744 /* Return true if DECL is a VAR_DECL that should be protected
kono
parents:
diff changeset
1745 by Address Sanitizer, by appending a red zone with protected
kono
parents:
diff changeset
1746 shadow memory after it and aligning it to at least
kono
parents:
diff changeset
1747 ASAN_RED_ZONE_SIZE bytes. */
kono
parents:
diff changeset
1748
kono
parents:
diff changeset
1749 bool
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1750 asan_protect_global (tree decl, bool ignore_decl_rtl_set_p)
111
kono
parents:
diff changeset
1751 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1752 if (!param_asan_globals)
111
kono
parents:
diff changeset
1753 return false;
kono
parents:
diff changeset
1754
kono
parents:
diff changeset
1755 rtx rtl, symbol;
kono
parents:
diff changeset
1756
kono
parents:
diff changeset
1757 if (TREE_CODE (decl) == STRING_CST)
kono
parents:
diff changeset
1758 {
kono
parents:
diff changeset
1759 /* Instrument all STRING_CSTs except those created
kono
parents:
diff changeset
1760 by asan_pp_string here. */
kono
parents:
diff changeset
1761 if (shadow_ptr_types[0] != NULL_TREE
kono
parents:
diff changeset
1762 && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
kono
parents:
diff changeset
1763 && TREE_TYPE (TREE_TYPE (decl)) == TREE_TYPE (shadow_ptr_types[0]))
kono
parents:
diff changeset
1764 return false;
kono
parents:
diff changeset
1765 return true;
kono
parents:
diff changeset
1766 }
kono
parents:
diff changeset
1767 if (!VAR_P (decl)
kono
parents:
diff changeset
1768 /* TLS vars aren't statically protectable. */
kono
parents:
diff changeset
1769 || DECL_THREAD_LOCAL_P (decl)
kono
parents:
diff changeset
1770 /* Externs will be protected elsewhere. */
kono
parents:
diff changeset
1771 || DECL_EXTERNAL (decl)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1772 /* PR sanitizer/81697: For architectures that use section anchors first
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1773 call to asan_protect_global may occur before DECL_RTL (decl) is set.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1774 We should ignore DECL_RTL_SET_P then, because otherwise the first call
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1775 to asan_protect_global will return FALSE and the following calls on the
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1776 same decl after setting DECL_RTL (decl) will return TRUE and we'll end
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1777 up with inconsistency at runtime. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1778 || (!DECL_RTL_SET_P (decl) && !ignore_decl_rtl_set_p)
111
kono
parents:
diff changeset
1779 /* Comdat vars pose an ABI problem, we can't know if
kono
parents:
diff changeset
1780 the var that is selected by the linker will have
kono
parents:
diff changeset
1781 padding or not. */
kono
parents:
diff changeset
1782 || DECL_ONE_ONLY (decl)
kono
parents:
diff changeset
1783 /* Similarly for common vars. People can use -fno-common.
kono
parents:
diff changeset
1784 Note: Linux kernel is built with -fno-common, so we do instrument
kono
parents:
diff changeset
1785 globals there even if it is C. */
kono
parents:
diff changeset
1786 || (DECL_COMMON (decl) && TREE_PUBLIC (decl))
kono
parents:
diff changeset
1787 /* Don't protect if using user section, often vars placed
kono
parents:
diff changeset
1788 into user section from multiple TUs are then assumed
kono
parents:
diff changeset
1789 to be an array of such vars, putting padding in there
kono
parents:
diff changeset
1790 breaks this assumption. */
kono
parents:
diff changeset
1791 || (DECL_SECTION_NAME (decl) != NULL
kono
parents:
diff changeset
1792 && !symtab_node::get (decl)->implicit_section
kono
parents:
diff changeset
1793 && !section_sanitized_p (DECL_SECTION_NAME (decl)))
kono
parents:
diff changeset
1794 || DECL_SIZE (decl) == 0
kono
parents:
diff changeset
1795 || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1796 || TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST
111
kono
parents:
diff changeset
1797 || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
kono
parents:
diff changeset
1798 || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE
kono
parents:
diff changeset
1799 || TREE_TYPE (decl) == ubsan_get_source_location_type ()
kono
parents:
diff changeset
1800 || is_odr_indicator (decl))
kono
parents:
diff changeset
1801 return false;
kono
parents:
diff changeset
1802
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1803 if (!ignore_decl_rtl_set_p || DECL_RTL_SET_P (decl))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1804 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1805
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1806 rtl = DECL_RTL (decl);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1807 if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1808 return false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1809 symbol = XEXP (rtl, 0);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1810
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1811 if (CONSTANT_POOL_ADDRESS_P (symbol)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1812 || TREE_CONSTANT_POOL_ADDRESS_P (symbol))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1813 return false;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1814 }
111
kono
parents:
diff changeset
1815
kono
parents:
diff changeset
1816 if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
kono
parents:
diff changeset
1817 return false;
kono
parents:
diff changeset
1818
kono
parents:
diff changeset
1819 if (!TARGET_SUPPORTS_ALIASES && asan_needs_local_alias (decl))
kono
parents:
diff changeset
1820 return false;
kono
parents:
diff changeset
1821
kono
parents:
diff changeset
1822 return true;
kono
parents:
diff changeset
1823 }
kono
parents:
diff changeset
1824
kono
parents:
diff changeset
1825 /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16,_n}.
kono
parents:
diff changeset
1826 IS_STORE is either 1 (for a store) or 0 (for a load). */
kono
parents:
diff changeset
1827
kono
parents:
diff changeset
1828 static tree
kono
parents:
diff changeset
1829 report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
kono
parents:
diff changeset
1830 int *nargs)
kono
parents:
diff changeset
1831 {
kono
parents:
diff changeset
1832 static enum built_in_function report[2][2][6]
kono
parents:
diff changeset
1833 = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
kono
parents:
diff changeset
1834 BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
kono
parents:
diff changeset
1835 BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N },
kono
parents:
diff changeset
1836 { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
kono
parents:
diff changeset
1837 BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
kono
parents:
diff changeset
1838 BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } },
kono
parents:
diff changeset
1839 { { BUILT_IN_ASAN_REPORT_LOAD1_NOABORT,
kono
parents:
diff changeset
1840 BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
kono
parents:
diff changeset
1841 BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
kono
parents:
diff changeset
1842 BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
kono
parents:
diff changeset
1843 BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
kono
parents:
diff changeset
1844 BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT },
kono
parents:
diff changeset
1845 { BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
kono
parents:
diff changeset
1846 BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
kono
parents:
diff changeset
1847 BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
kono
parents:
diff changeset
1848 BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
kono
parents:
diff changeset
1849 BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
kono
parents:
diff changeset
1850 BUILT_IN_ASAN_REPORT_STORE_N_NOABORT } } };
kono
parents:
diff changeset
1851 if (size_in_bytes == -1)
kono
parents:
diff changeset
1852 {
kono
parents:
diff changeset
1853 *nargs = 2;
kono
parents:
diff changeset
1854 return builtin_decl_implicit (report[recover_p][is_store][5]);
kono
parents:
diff changeset
1855 }
kono
parents:
diff changeset
1856 *nargs = 1;
kono
parents:
diff changeset
1857 int size_log2 = exact_log2 (size_in_bytes);
kono
parents:
diff changeset
1858 return builtin_decl_implicit (report[recover_p][is_store][size_log2]);
kono
parents:
diff changeset
1859 }
kono
parents:
diff changeset
1860
kono
parents:
diff changeset
1861 /* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
kono
parents:
diff changeset
1862 IS_STORE is either 1 (for a store) or 0 (for a load). */
kono
parents:
diff changeset
1863
kono
parents:
diff changeset
1864 static tree
kono
parents:
diff changeset
1865 check_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
kono
parents:
diff changeset
1866 int *nargs)
kono
parents:
diff changeset
1867 {
kono
parents:
diff changeset
1868 static enum built_in_function check[2][2][6]
kono
parents:
diff changeset
1869 = { { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
kono
parents:
diff changeset
1870 BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
kono
parents:
diff changeset
1871 BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
kono
parents:
diff changeset
1872 { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
kono
parents:
diff changeset
1873 BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
kono
parents:
diff changeset
1874 BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } },
kono
parents:
diff changeset
1875 { { BUILT_IN_ASAN_LOAD1_NOABORT,
kono
parents:
diff changeset
1876 BUILT_IN_ASAN_LOAD2_NOABORT,
kono
parents:
diff changeset
1877 BUILT_IN_ASAN_LOAD4_NOABORT,
kono
parents:
diff changeset
1878 BUILT_IN_ASAN_LOAD8_NOABORT,
kono
parents:
diff changeset
1879 BUILT_IN_ASAN_LOAD16_NOABORT,
kono
parents:
diff changeset
1880 BUILT_IN_ASAN_LOADN_NOABORT },
kono
parents:
diff changeset
1881 { BUILT_IN_ASAN_STORE1_NOABORT,
kono
parents:
diff changeset
1882 BUILT_IN_ASAN_STORE2_NOABORT,
kono
parents:
diff changeset
1883 BUILT_IN_ASAN_STORE4_NOABORT,
kono
parents:
diff changeset
1884 BUILT_IN_ASAN_STORE8_NOABORT,
kono
parents:
diff changeset
1885 BUILT_IN_ASAN_STORE16_NOABORT,
kono
parents:
diff changeset
1886 BUILT_IN_ASAN_STOREN_NOABORT } } };
kono
parents:
diff changeset
1887 if (size_in_bytes == -1)
kono
parents:
diff changeset
1888 {
kono
parents:
diff changeset
1889 *nargs = 2;
kono
parents:
diff changeset
1890 return builtin_decl_implicit (check[recover_p][is_store][5]);
kono
parents:
diff changeset
1891 }
kono
parents:
diff changeset
1892 *nargs = 1;
kono
parents:
diff changeset
1893 int size_log2 = exact_log2 (size_in_bytes);
kono
parents:
diff changeset
1894 return builtin_decl_implicit (check[recover_p][is_store][size_log2]);
kono
parents:
diff changeset
1895 }
kono
parents:
diff changeset
1896
kono
parents:
diff changeset
1897 /* Split the current basic block and create a condition statement
kono
parents:
diff changeset
1898 insertion point right before or after the statement pointed to by
kono
parents:
diff changeset
1899 ITER. Return an iterator to the point at which the caller might
kono
parents:
diff changeset
1900 safely insert the condition statement.
kono
parents:
diff changeset
1901
kono
parents:
diff changeset
1902 THEN_BLOCK must be set to the address of an uninitialized instance
kono
parents:
diff changeset
1903 of basic_block. The function will then set *THEN_BLOCK to the
kono
parents:
diff changeset
1904 'then block' of the condition statement to be inserted by the
kono
parents:
diff changeset
1905 caller.
kono
parents:
diff changeset
1906
kono
parents:
diff changeset
1907 If CREATE_THEN_FALLTHRU_EDGE is false, no edge will be created from
kono
parents:
diff changeset
1908 *THEN_BLOCK to *FALLTHROUGH_BLOCK.
kono
parents:
diff changeset
1909
kono
parents:
diff changeset
1910 Similarly, the function will set *FALLTRHOUGH_BLOCK to the 'else
kono
parents:
diff changeset
1911 block' of the condition statement to be inserted by the caller.
kono
parents:
diff changeset
1912
kono
parents:
diff changeset
1913 Note that *FALLTHROUGH_BLOCK is a new block that contains the
kono
parents:
diff changeset
1914 statements starting from *ITER, and *THEN_BLOCK is a new empty
kono
parents:
diff changeset
1915 block.
kono
parents:
diff changeset
1916
kono
parents:
diff changeset
1917 *ITER is adjusted to point to always point to the first statement
kono
parents:
diff changeset
1918 of the basic block * FALLTHROUGH_BLOCK. That statement is the
kono
parents:
diff changeset
1919 same as what ITER was pointing to prior to calling this function,
kono
parents:
diff changeset
1920 if BEFORE_P is true; otherwise, it is its following statement. */
kono
parents:
diff changeset
1921
kono
parents:
diff changeset
1922 gimple_stmt_iterator
kono
parents:
diff changeset
1923 create_cond_insert_point (gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1924 bool before_p,
kono
parents:
diff changeset
1925 bool then_more_likely_p,
kono
parents:
diff changeset
1926 bool create_then_fallthru_edge,
kono
parents:
diff changeset
1927 basic_block *then_block,
kono
parents:
diff changeset
1928 basic_block *fallthrough_block)
kono
parents:
diff changeset
1929 {
kono
parents:
diff changeset
1930 gimple_stmt_iterator gsi = *iter;
kono
parents:
diff changeset
1931
kono
parents:
diff changeset
1932 if (!gsi_end_p (gsi) && before_p)
kono
parents:
diff changeset
1933 gsi_prev (&gsi);
kono
parents:
diff changeset
1934
kono
parents:
diff changeset
1935 basic_block cur_bb = gsi_bb (*iter);
kono
parents:
diff changeset
1936
kono
parents:
diff changeset
1937 edge e = split_block (cur_bb, gsi_stmt (gsi));
kono
parents:
diff changeset
1938
kono
parents:
diff changeset
1939 /* Get a hold on the 'condition block', the 'then block' and the
kono
parents:
diff changeset
1940 'else block'. */
kono
parents:
diff changeset
1941 basic_block cond_bb = e->src;
kono
parents:
diff changeset
1942 basic_block fallthru_bb = e->dest;
kono
parents:
diff changeset
1943 basic_block then_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
1944 if (current_loops)
kono
parents:
diff changeset
1945 {
kono
parents:
diff changeset
1946 add_bb_to_loop (then_bb, cond_bb->loop_father);
kono
parents:
diff changeset
1947 loops_state_set (LOOPS_NEED_FIXUP);
kono
parents:
diff changeset
1948 }
kono
parents:
diff changeset
1949
kono
parents:
diff changeset
1950 /* Set up the newly created 'then block'. */
kono
parents:
diff changeset
1951 e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1952 profile_probability fallthrough_probability
kono
parents:
diff changeset
1953 = then_more_likely_p
kono
parents:
diff changeset
1954 ? profile_probability::very_unlikely ()
kono
parents:
diff changeset
1955 : profile_probability::very_likely ();
kono
parents:
diff changeset
1956 e->probability = fallthrough_probability.invert ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1957 then_bb->count = e->count ();
111
kono
parents:
diff changeset
1958 if (create_then_fallthru_edge)
kono
parents:
diff changeset
1959 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
1960
kono
parents:
diff changeset
1961 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
1962 e = find_edge (cond_bb, fallthru_bb);
kono
parents:
diff changeset
1963 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
1964 e->probability = fallthrough_probability;
kono
parents:
diff changeset
1965
kono
parents:
diff changeset
1966 /* Update dominance info for the newly created then_bb; note that
kono
parents:
diff changeset
1967 fallthru_bb's dominance info has already been updated by
kono
parents:
diff changeset
1968 split_bock. */
kono
parents:
diff changeset
1969 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
1970 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
kono
parents:
diff changeset
1971
kono
parents:
diff changeset
1972 *then_block = then_bb;
kono
parents:
diff changeset
1973 *fallthrough_block = fallthru_bb;
kono
parents:
diff changeset
1974 *iter = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
1975
kono
parents:
diff changeset
1976 return gsi_last_bb (cond_bb);
kono
parents:
diff changeset
1977 }
kono
parents:
diff changeset
1978
kono
parents:
diff changeset
1979 /* Insert an if condition followed by a 'then block' right before the
kono
parents:
diff changeset
1980 statement pointed to by ITER. The fallthrough block -- which is the
kono
parents:
diff changeset
1981 else block of the condition as well as the destination of the
kono
parents:
diff changeset
1982 outcoming edge of the 'then block' -- starts with the statement
kono
parents:
diff changeset
1983 pointed to by ITER.
kono
parents:
diff changeset
1984
kono
parents:
diff changeset
1985 COND is the condition of the if.
kono
parents:
diff changeset
1986
kono
parents:
diff changeset
1987 If THEN_MORE_LIKELY_P is true, the probability of the edge to the
kono
parents:
diff changeset
1988 'then block' is higher than the probability of the edge to the
kono
parents:
diff changeset
1989 fallthrough block.
kono
parents:
diff changeset
1990
kono
parents:
diff changeset
1991 Upon completion of the function, *THEN_BB is set to the newly
kono
parents:
diff changeset
1992 inserted 'then block' and similarly, *FALLTHROUGH_BB is set to the
kono
parents:
diff changeset
1993 fallthrough block.
kono
parents:
diff changeset
1994
kono
parents:
diff changeset
1995 *ITER is adjusted to still point to the same statement it was
kono
parents:
diff changeset
1996 pointing to initially. */
kono
parents:
diff changeset
1997
kono
parents:
diff changeset
1998 static void
kono
parents:
diff changeset
1999 insert_if_then_before_iter (gcond *cond,
kono
parents:
diff changeset
2000 gimple_stmt_iterator *iter,
kono
parents:
diff changeset
2001 bool then_more_likely_p,
kono
parents:
diff changeset
2002 basic_block *then_bb,
kono
parents:
diff changeset
2003 basic_block *fallthrough_bb)
kono
parents:
diff changeset
2004 {
kono
parents:
diff changeset
2005 gimple_stmt_iterator cond_insert_point =
kono
parents:
diff changeset
2006 create_cond_insert_point (iter,
kono
parents:
diff changeset
2007 /*before_p=*/true,
kono
parents:
diff changeset
2008 then_more_likely_p,
kono
parents:
diff changeset
2009 /*create_then_fallthru_edge=*/true,
kono
parents:
diff changeset
2010 then_bb,
kono
parents:
diff changeset
2011 fallthrough_bb);
kono
parents:
diff changeset
2012 gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT);
kono
parents:
diff changeset
2013 }
kono
parents:
diff changeset
2014
kono
parents:
diff changeset
2015 /* Build (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset ().
kono
parents:
diff changeset
2016 If RETURN_ADDRESS is set to true, return memory location instread
kono
parents:
diff changeset
2017 of a value in the shadow memory. */
kono
parents:
diff changeset
2018
kono
parents:
diff changeset
2019 static tree
kono
parents:
diff changeset
2020 build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
kono
parents:
diff changeset
2021 tree base_addr, tree shadow_ptr_type,
kono
parents:
diff changeset
2022 bool return_address = false)
kono
parents:
diff changeset
2023 {
kono
parents:
diff changeset
2024 tree t, uintptr_type = TREE_TYPE (base_addr);
kono
parents:
diff changeset
2025 tree shadow_type = TREE_TYPE (shadow_ptr_type);
kono
parents:
diff changeset
2026 gimple *g;
kono
parents:
diff changeset
2027
kono
parents:
diff changeset
2028 t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
2029 g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
kono
parents:
diff changeset
2030 base_addr, t);
kono
parents:
diff changeset
2031 gimple_set_location (g, location);
kono
parents:
diff changeset
2032 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2033
kono
parents:
diff changeset
2034 t = build_int_cst (uintptr_type, asan_shadow_offset ());
kono
parents:
diff changeset
2035 g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
kono
parents:
diff changeset
2036 gimple_assign_lhs (g), t);
kono
parents:
diff changeset
2037 gimple_set_location (g, location);
kono
parents:
diff changeset
2038 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2039
kono
parents:
diff changeset
2040 g = gimple_build_assign (make_ssa_name (shadow_ptr_type), NOP_EXPR,
kono
parents:
diff changeset
2041 gimple_assign_lhs (g));
kono
parents:
diff changeset
2042 gimple_set_location (g, location);
kono
parents:
diff changeset
2043 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2044
kono
parents:
diff changeset
2045 if (!return_address)
kono
parents:
diff changeset
2046 {
kono
parents:
diff changeset
2047 t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
kono
parents:
diff changeset
2048 build_int_cst (shadow_ptr_type, 0));
kono
parents:
diff changeset
2049 g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
kono
parents:
diff changeset
2050 gimple_set_location (g, location);
kono
parents:
diff changeset
2051 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2052 }
kono
parents:
diff changeset
2053
kono
parents:
diff changeset
2054 return gimple_assign_lhs (g);
kono
parents:
diff changeset
2055 }
kono
parents:
diff changeset
2056
kono
parents:
diff changeset
2057 /* BASE can already be an SSA_NAME; in that case, do not create a
kono
parents:
diff changeset
2058 new SSA_NAME for it. */
kono
parents:
diff changeset
2059
kono
parents:
diff changeset
2060 static tree
kono
parents:
diff changeset
2061 maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
2062 bool before_p)
kono
parents:
diff changeset
2063 {
kono
parents:
diff changeset
2064 if (TREE_CODE (base) == SSA_NAME)
kono
parents:
diff changeset
2065 return base;
kono
parents:
diff changeset
2066 gimple *g = gimple_build_assign (make_ssa_name (TREE_TYPE (base)),
kono
parents:
diff changeset
2067 TREE_CODE (base), base);
kono
parents:
diff changeset
2068 gimple_set_location (g, loc);
kono
parents:
diff changeset
2069 if (before_p)
kono
parents:
diff changeset
2070 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2071 else
kono
parents:
diff changeset
2072 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2073 return gimple_assign_lhs (g);
kono
parents:
diff changeset
2074 }
kono
parents:
diff changeset
2075
kono
parents:
diff changeset
2076 /* LEN can already have necessary size and precision;
kono
parents:
diff changeset
2077 in that case, do not create a new variable. */
kono
parents:
diff changeset
2078
kono
parents:
diff changeset
2079 tree
kono
parents:
diff changeset
2080 maybe_cast_to_ptrmode (location_t loc, tree len, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
2081 bool before_p)
kono
parents:
diff changeset
2082 {
kono
parents:
diff changeset
2083 if (ptrofftype_p (len))
kono
parents:
diff changeset
2084 return len;
kono
parents:
diff changeset
2085 gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
2086 NOP_EXPR, len);
kono
parents:
diff changeset
2087 gimple_set_location (g, loc);
kono
parents:
diff changeset
2088 if (before_p)
kono
parents:
diff changeset
2089 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2090 else
kono
parents:
diff changeset
2091 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2092 return gimple_assign_lhs (g);
kono
parents:
diff changeset
2093 }
kono
parents:
diff changeset
2094
kono
parents:
diff changeset
2095 /* Instrument the memory access instruction BASE. Insert new
kono
parents:
diff changeset
2096 statements before or after ITER.
kono
parents:
diff changeset
2097
kono
parents:
diff changeset
2098 Note that the memory access represented by BASE can be either an
kono
parents:
diff changeset
2099 SSA_NAME, or a non-SSA expression. LOCATION is the source code
kono
parents:
diff changeset
2100 location. IS_STORE is TRUE for a store, FALSE for a load.
kono
parents:
diff changeset
2101 BEFORE_P is TRUE for inserting the instrumentation code before
kono
parents:
diff changeset
2102 ITER, FALSE for inserting it after ITER. IS_SCALAR_ACCESS is TRUE
kono
parents:
diff changeset
2103 for a scalar memory access and FALSE for memory region access.
kono
parents:
diff changeset
2104 NON_ZERO_P is TRUE if memory region is guaranteed to have non-zero
kono
parents:
diff changeset
2105 length. ALIGN tells alignment of accessed memory object.
kono
parents:
diff changeset
2106
kono
parents:
diff changeset
2107 START_INSTRUMENTED and END_INSTRUMENTED are TRUE if start/end of
kono
parents:
diff changeset
2108 memory region have already been instrumented.
kono
parents:
diff changeset
2109
kono
parents:
diff changeset
2110 If BEFORE_P is TRUE, *ITER is arranged to still point to the
kono
parents:
diff changeset
2111 statement it was pointing to prior to calling this function,
kono
parents:
diff changeset
2112 otherwise, it points to the statement logically following it. */
kono
parents:
diff changeset
2113
kono
parents:
diff changeset
2114 static void
kono
parents:
diff changeset
2115 build_check_stmt (location_t loc, tree base, tree len,
kono
parents:
diff changeset
2116 HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
2117 bool is_non_zero_len, bool before_p, bool is_store,
kono
parents:
diff changeset
2118 bool is_scalar_access, unsigned int align = 0)
kono
parents:
diff changeset
2119 {
kono
parents:
diff changeset
2120 gimple_stmt_iterator gsi = *iter;
kono
parents:
diff changeset
2121 gimple *g;
kono
parents:
diff changeset
2122
kono
parents:
diff changeset
2123 gcc_assert (!(size_in_bytes > 0 && !is_non_zero_len));
kono
parents:
diff changeset
2124
kono
parents:
diff changeset
2125 gsi = *iter;
kono
parents:
diff changeset
2126
kono
parents:
diff changeset
2127 base = unshare_expr (base);
kono
parents:
diff changeset
2128 base = maybe_create_ssa_name (loc, base, &gsi, before_p);
kono
parents:
diff changeset
2129
kono
parents:
diff changeset
2130 if (len)
kono
parents:
diff changeset
2131 {
kono
parents:
diff changeset
2132 len = unshare_expr (len);
kono
parents:
diff changeset
2133 len = maybe_cast_to_ptrmode (loc, len, iter, before_p);
kono
parents:
diff changeset
2134 }
kono
parents:
diff changeset
2135 else
kono
parents:
diff changeset
2136 {
kono
parents:
diff changeset
2137 gcc_assert (size_in_bytes != -1);
kono
parents:
diff changeset
2138 len = build_int_cst (pointer_sized_int_node, size_in_bytes);
kono
parents:
diff changeset
2139 }
kono
parents:
diff changeset
2140
kono
parents:
diff changeset
2141 if (size_in_bytes > 1)
kono
parents:
diff changeset
2142 {
kono
parents:
diff changeset
2143 if ((size_in_bytes & (size_in_bytes - 1)) != 0
kono
parents:
diff changeset
2144 || size_in_bytes > 16)
kono
parents:
diff changeset
2145 is_scalar_access = false;
kono
parents:
diff changeset
2146 else if (align && align < size_in_bytes * BITS_PER_UNIT)
kono
parents:
diff changeset
2147 {
kono
parents:
diff changeset
2148 /* On non-strict alignment targets, if
kono
parents:
diff changeset
2149 16-byte access is just 8-byte aligned,
kono
parents:
diff changeset
2150 this will result in misaligned shadow
kono
parents:
diff changeset
2151 memory 2 byte load, but otherwise can
kono
parents:
diff changeset
2152 be handled using one read. */
kono
parents:
diff changeset
2153 if (size_in_bytes != 16
kono
parents:
diff changeset
2154 || STRICT_ALIGNMENT
kono
parents:
diff changeset
2155 || align < 8 * BITS_PER_UNIT)
kono
parents:
diff changeset
2156 is_scalar_access = false;
kono
parents:
diff changeset
2157 }
kono
parents:
diff changeset
2158 }
kono
parents:
diff changeset
2159
kono
parents:
diff changeset
2160 HOST_WIDE_INT flags = 0;
kono
parents:
diff changeset
2161 if (is_store)
kono
parents:
diff changeset
2162 flags |= ASAN_CHECK_STORE;
kono
parents:
diff changeset
2163 if (is_non_zero_len)
kono
parents:
diff changeset
2164 flags |= ASAN_CHECK_NON_ZERO_LEN;
kono
parents:
diff changeset
2165 if (is_scalar_access)
kono
parents:
diff changeset
2166 flags |= ASAN_CHECK_SCALAR_ACCESS;
kono
parents:
diff changeset
2167
kono
parents:
diff changeset
2168 g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
kono
parents:
diff changeset
2169 build_int_cst (integer_type_node, flags),
kono
parents:
diff changeset
2170 base, len,
kono
parents:
diff changeset
2171 build_int_cst (integer_type_node,
kono
parents:
diff changeset
2172 align / BITS_PER_UNIT));
kono
parents:
diff changeset
2173 gimple_set_location (g, loc);
kono
parents:
diff changeset
2174 if (before_p)
kono
parents:
diff changeset
2175 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2176 else
kono
parents:
diff changeset
2177 {
kono
parents:
diff changeset
2178 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2179 gsi_next (&gsi);
kono
parents:
diff changeset
2180 *iter = gsi;
kono
parents:
diff changeset
2181 }
kono
parents:
diff changeset
2182 }
kono
parents:
diff changeset
2183
kono
parents:
diff changeset
2184 /* If T represents a memory access, add instrumentation code before ITER.
kono
parents:
diff changeset
2185 LOCATION is source code location.
kono
parents:
diff changeset
2186 IS_STORE is either TRUE (for a store) or FALSE (for a load). */
kono
parents:
diff changeset
2187
kono
parents:
diff changeset
2188 static void
kono
parents:
diff changeset
2189 instrument_derefs (gimple_stmt_iterator *iter, tree t,
kono
parents:
diff changeset
2190 location_t location, bool is_store)
kono
parents:
diff changeset
2191 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2192 if (is_store && !param_asan_instrument_writes)
111
kono
parents:
diff changeset
2193 return;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2194 if (!is_store && !param_asan_instrument_reads)
111
kono
parents:
diff changeset
2195 return;
kono
parents:
diff changeset
2196
kono
parents:
diff changeset
2197 tree type, base;
kono
parents:
diff changeset
2198 HOST_WIDE_INT size_in_bytes;
kono
parents:
diff changeset
2199 if (location == UNKNOWN_LOCATION)
kono
parents:
diff changeset
2200 location = EXPR_LOCATION (t);
kono
parents:
diff changeset
2201
kono
parents:
diff changeset
2202 type = TREE_TYPE (t);
kono
parents:
diff changeset
2203 switch (TREE_CODE (t))
kono
parents:
diff changeset
2204 {
kono
parents:
diff changeset
2205 case ARRAY_REF:
kono
parents:
diff changeset
2206 case COMPONENT_REF:
kono
parents:
diff changeset
2207 case INDIRECT_REF:
kono
parents:
diff changeset
2208 case MEM_REF:
kono
parents:
diff changeset
2209 case VAR_DECL:
kono
parents:
diff changeset
2210 case BIT_FIELD_REF:
kono
parents:
diff changeset
2211 break;
kono
parents:
diff changeset
2212 /* FALLTHRU */
kono
parents:
diff changeset
2213 default:
kono
parents:
diff changeset
2214 return;
kono
parents:
diff changeset
2215 }
kono
parents:
diff changeset
2216
kono
parents:
diff changeset
2217 size_in_bytes = int_size_in_bytes (type);
kono
parents:
diff changeset
2218 if (size_in_bytes <= 0)
kono
parents:
diff changeset
2219 return;
kono
parents:
diff changeset
2220
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2221 poly_int64 bitsize, bitpos;
111
kono
parents:
diff changeset
2222 tree offset;
kono
parents:
diff changeset
2223 machine_mode mode;
kono
parents:
diff changeset
2224 int unsignedp, reversep, volatilep = 0;
kono
parents:
diff changeset
2225 tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
2226 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
2227
kono
parents:
diff changeset
2228 if (TREE_CODE (t) == COMPONENT_REF
kono
parents:
diff changeset
2229 && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
kono
parents:
diff changeset
2230 {
kono
parents:
diff changeset
2231 tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
kono
parents:
diff changeset
2232 instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
kono
parents:
diff changeset
2233 TREE_OPERAND (t, 0), repr,
kono
parents:
diff changeset
2234 TREE_OPERAND (t, 2)),
kono
parents:
diff changeset
2235 location, is_store);
kono
parents:
diff changeset
2236 return;
kono
parents:
diff changeset
2237 }
kono
parents:
diff changeset
2238
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2239 if (!multiple_p (bitpos, BITS_PER_UNIT)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2240 || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
111
kono
parents:
diff changeset
2241 return;
kono
parents:
diff changeset
2242
kono
parents:
diff changeset
2243 if (VAR_P (inner) && DECL_HARD_REGISTER (inner))
kono
parents:
diff changeset
2244 return;
kono
parents:
diff changeset
2245
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2246 poly_int64 decl_size;
111
kono
parents:
diff changeset
2247 if (VAR_P (inner)
kono
parents:
diff changeset
2248 && offset == NULL_TREE
kono
parents:
diff changeset
2249 && DECL_SIZE (inner)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2250 && poly_int_tree_p (DECL_SIZE (inner), &decl_size)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2251 && known_subrange_p (bitpos, bitsize, 0, decl_size))
111
kono
parents:
diff changeset
2252 {
kono
parents:
diff changeset
2253 if (DECL_THREAD_LOCAL_P (inner))
kono
parents:
diff changeset
2254 return;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2255 if (!param_asan_globals && is_global_var (inner))
111
kono
parents:
diff changeset
2256 return;
kono
parents:
diff changeset
2257 if (!TREE_STATIC (inner))
kono
parents:
diff changeset
2258 {
kono
parents:
diff changeset
2259 /* Automatic vars in the current function will be always
kono
parents:
diff changeset
2260 accessible. */
kono
parents:
diff changeset
2261 if (decl_function_context (inner) == current_function_decl
kono
parents:
diff changeset
2262 && (!asan_sanitize_use_after_scope ()
kono
parents:
diff changeset
2263 || !TREE_ADDRESSABLE (inner)))
kono
parents:
diff changeset
2264 return;
kono
parents:
diff changeset
2265 }
kono
parents:
diff changeset
2266 /* Always instrument external vars, they might be dynamically
kono
parents:
diff changeset
2267 initialized. */
kono
parents:
diff changeset
2268 else if (!DECL_EXTERNAL (inner))
kono
parents:
diff changeset
2269 {
kono
parents:
diff changeset
2270 /* For static vars if they are known not to be dynamically
kono
parents:
diff changeset
2271 initialized, they will be always accessible. */
kono
parents:
diff changeset
2272 varpool_node *vnode = varpool_node::get (inner);
kono
parents:
diff changeset
2273 if (vnode && !vnode->dynamically_initialized)
kono
parents:
diff changeset
2274 return;
kono
parents:
diff changeset
2275 }
kono
parents:
diff changeset
2276 }
kono
parents:
diff changeset
2277
kono
parents:
diff changeset
2278 base = build_fold_addr_expr (t);
kono
parents:
diff changeset
2279 if (!has_mem_ref_been_instrumented (base, size_in_bytes))
kono
parents:
diff changeset
2280 {
kono
parents:
diff changeset
2281 unsigned int align = get_object_alignment (t);
kono
parents:
diff changeset
2282 build_check_stmt (location, base, NULL_TREE, size_in_bytes, iter,
kono
parents:
diff changeset
2283 /*is_non_zero_len*/size_in_bytes > 0, /*before_p=*/true,
kono
parents:
diff changeset
2284 is_store, /*is_scalar_access*/true, align);
kono
parents:
diff changeset
2285 update_mem_ref_hash_table (base, size_in_bytes);
kono
parents:
diff changeset
2286 update_mem_ref_hash_table (t, size_in_bytes);
kono
parents:
diff changeset
2287 }
kono
parents:
diff changeset
2288
kono
parents:
diff changeset
2289 }
kono
parents:
diff changeset
2290
kono
parents:
diff changeset
2291 /* Insert a memory reference into the hash table if access length
kono
parents:
diff changeset
2292 can be determined in compile time. */
kono
parents:
diff changeset
2293
kono
parents:
diff changeset
2294 static void
kono
parents:
diff changeset
2295 maybe_update_mem_ref_hash_table (tree base, tree len)
kono
parents:
diff changeset
2296 {
kono
parents:
diff changeset
2297 if (!POINTER_TYPE_P (TREE_TYPE (base))
kono
parents:
diff changeset
2298 || !INTEGRAL_TYPE_P (TREE_TYPE (len)))
kono
parents:
diff changeset
2299 return;
kono
parents:
diff changeset
2300
kono
parents:
diff changeset
2301 HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
kono
parents:
diff changeset
2302
kono
parents:
diff changeset
2303 if (size_in_bytes != -1)
kono
parents:
diff changeset
2304 update_mem_ref_hash_table (base, size_in_bytes);
kono
parents:
diff changeset
2305 }
kono
parents:
diff changeset
2306
kono
parents:
diff changeset
2307 /* Instrument an access to a contiguous memory region that starts at
kono
parents:
diff changeset
2308 the address pointed to by BASE, over a length of LEN (expressed in
kono
parents:
diff changeset
2309 the sizeof (*BASE) bytes). ITER points to the instruction before
kono
parents:
diff changeset
2310 which the instrumentation instructions must be inserted. LOCATION
kono
parents:
diff changeset
2311 is the source location that the instrumentation instructions must
kono
parents:
diff changeset
2312 have. If IS_STORE is true, then the memory access is a store;
kono
parents:
diff changeset
2313 otherwise, it's a load. */
kono
parents:
diff changeset
2314
kono
parents:
diff changeset
2315 static void
kono
parents:
diff changeset
2316 instrument_mem_region_access (tree base, tree len,
kono
parents:
diff changeset
2317 gimple_stmt_iterator *iter,
kono
parents:
diff changeset
2318 location_t location, bool is_store)
kono
parents:
diff changeset
2319 {
kono
parents:
diff changeset
2320 if (!POINTER_TYPE_P (TREE_TYPE (base))
kono
parents:
diff changeset
2321 || !INTEGRAL_TYPE_P (TREE_TYPE (len))
kono
parents:
diff changeset
2322 || integer_zerop (len))
kono
parents:
diff changeset
2323 return;
kono
parents:
diff changeset
2324
kono
parents:
diff changeset
2325 HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
kono
parents:
diff changeset
2326
kono
parents:
diff changeset
2327 if ((size_in_bytes == -1)
kono
parents:
diff changeset
2328 || !has_mem_ref_been_instrumented (base, size_in_bytes))
kono
parents:
diff changeset
2329 {
kono
parents:
diff changeset
2330 build_check_stmt (location, base, len, size_in_bytes, iter,
kono
parents:
diff changeset
2331 /*is_non_zero_len*/size_in_bytes > 0, /*before_p*/true,
kono
parents:
diff changeset
2332 is_store, /*is_scalar_access*/false, /*align*/0);
kono
parents:
diff changeset
2333 }
kono
parents:
diff changeset
2334
kono
parents:
diff changeset
2335 maybe_update_mem_ref_hash_table (base, len);
kono
parents:
diff changeset
2336 *iter = gsi_for_stmt (gsi_stmt (*iter));
kono
parents:
diff changeset
2337 }
kono
parents:
diff changeset
2338
kono
parents:
diff changeset
2339 /* Instrument the call to a built-in memory access function that is
kono
parents:
diff changeset
2340 pointed to by the iterator ITER.
kono
parents:
diff changeset
2341
kono
parents:
diff changeset
2342 Upon completion, return TRUE iff *ITER has been advanced to the
kono
parents:
diff changeset
2343 statement following the one it was originally pointing to. */
kono
parents:
diff changeset
2344
kono
parents:
diff changeset
2345 static bool
kono
parents:
diff changeset
2346 instrument_builtin_call (gimple_stmt_iterator *iter)
kono
parents:
diff changeset
2347 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2348 if (!param_asan_memintrin)
111
kono
parents:
diff changeset
2349 return false;
kono
parents:
diff changeset
2350
kono
parents:
diff changeset
2351 bool iter_advanced_p = false;
kono
parents:
diff changeset
2352 gcall *call = as_a <gcall *> (gsi_stmt (*iter));
kono
parents:
diff changeset
2353
kono
parents:
diff changeset
2354 gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
kono
parents:
diff changeset
2355
kono
parents:
diff changeset
2356 location_t loc = gimple_location (call);
kono
parents:
diff changeset
2357
kono
parents:
diff changeset
2358 asan_mem_ref src0, src1, dest;
kono
parents:
diff changeset
2359 asan_mem_ref_init (&src0, NULL, 1);
kono
parents:
diff changeset
2360 asan_mem_ref_init (&src1, NULL, 1);
kono
parents:
diff changeset
2361 asan_mem_ref_init (&dest, NULL, 1);
kono
parents:
diff changeset
2362
kono
parents:
diff changeset
2363 tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
kono
parents:
diff changeset
2364 bool src0_is_store = false, src1_is_store = false, dest_is_store = false,
kono
parents:
diff changeset
2365 dest_is_deref = false, intercepted_p = true;
kono
parents:
diff changeset
2366
kono
parents:
diff changeset
2367 if (get_mem_refs_of_builtin_call (call,
kono
parents:
diff changeset
2368 &src0, &src0_len, &src0_is_store,
kono
parents:
diff changeset
2369 &src1, &src1_len, &src1_is_store,
kono
parents:
diff changeset
2370 &dest, &dest_len, &dest_is_store,
kono
parents:
diff changeset
2371 &dest_is_deref, &intercepted_p, iter))
kono
parents:
diff changeset
2372 {
kono
parents:
diff changeset
2373 if (dest_is_deref)
kono
parents:
diff changeset
2374 {
kono
parents:
diff changeset
2375 instrument_derefs (iter, dest.start, loc, dest_is_store);
kono
parents:
diff changeset
2376 gsi_next (iter);
kono
parents:
diff changeset
2377 iter_advanced_p = true;
kono
parents:
diff changeset
2378 }
kono
parents:
diff changeset
2379 else if (!intercepted_p
kono
parents:
diff changeset
2380 && (src0_len || src1_len || dest_len))
kono
parents:
diff changeset
2381 {
kono
parents:
diff changeset
2382 if (src0.start != NULL_TREE)
kono
parents:
diff changeset
2383 instrument_mem_region_access (src0.start, src0_len,
kono
parents:
diff changeset
2384 iter, loc, /*is_store=*/false);
kono
parents:
diff changeset
2385 if (src1.start != NULL_TREE)
kono
parents:
diff changeset
2386 instrument_mem_region_access (src1.start, src1_len,
kono
parents:
diff changeset
2387 iter, loc, /*is_store=*/false);
kono
parents:
diff changeset
2388 if (dest.start != NULL_TREE)
kono
parents:
diff changeset
2389 instrument_mem_region_access (dest.start, dest_len,
kono
parents:
diff changeset
2390 iter, loc, /*is_store=*/true);
kono
parents:
diff changeset
2391
kono
parents:
diff changeset
2392 *iter = gsi_for_stmt (call);
kono
parents:
diff changeset
2393 gsi_next (iter);
kono
parents:
diff changeset
2394 iter_advanced_p = true;
kono
parents:
diff changeset
2395 }
kono
parents:
diff changeset
2396 else
kono
parents:
diff changeset
2397 {
kono
parents:
diff changeset
2398 if (src0.start != NULL_TREE)
kono
parents:
diff changeset
2399 maybe_update_mem_ref_hash_table (src0.start, src0_len);
kono
parents:
diff changeset
2400 if (src1.start != NULL_TREE)
kono
parents:
diff changeset
2401 maybe_update_mem_ref_hash_table (src1.start, src1_len);
kono
parents:
diff changeset
2402 if (dest.start != NULL_TREE)
kono
parents:
diff changeset
2403 maybe_update_mem_ref_hash_table (dest.start, dest_len);
kono
parents:
diff changeset
2404 }
kono
parents:
diff changeset
2405 }
kono
parents:
diff changeset
2406 return iter_advanced_p;
kono
parents:
diff changeset
2407 }
kono
parents:
diff changeset
2408
kono
parents:
diff changeset
2409 /* Instrument the assignment statement ITER if it is subject to
kono
parents:
diff changeset
2410 instrumentation. Return TRUE iff instrumentation actually
kono
parents:
diff changeset
2411 happened. In that case, the iterator ITER is advanced to the next
kono
parents:
diff changeset
2412 logical expression following the one initially pointed to by ITER,
kono
parents:
diff changeset
2413 and the relevant memory reference that which access has been
kono
parents:
diff changeset
2414 instrumented is added to the memory references hash table. */
kono
parents:
diff changeset
2415
kono
parents:
diff changeset
2416 static bool
kono
parents:
diff changeset
2417 maybe_instrument_assignment (gimple_stmt_iterator *iter)
kono
parents:
diff changeset
2418 {
kono
parents:
diff changeset
2419 gimple *s = gsi_stmt (*iter);
kono
parents:
diff changeset
2420
kono
parents:
diff changeset
2421 gcc_assert (gimple_assign_single_p (s));
kono
parents:
diff changeset
2422
kono
parents:
diff changeset
2423 tree ref_expr = NULL_TREE;
kono
parents:
diff changeset
2424 bool is_store, is_instrumented = false;
kono
parents:
diff changeset
2425
kono
parents:
diff changeset
2426 if (gimple_store_p (s))
kono
parents:
diff changeset
2427 {
kono
parents:
diff changeset
2428 ref_expr = gimple_assign_lhs (s);
kono
parents:
diff changeset
2429 is_store = true;
kono
parents:
diff changeset
2430 instrument_derefs (iter, ref_expr,
kono
parents:
diff changeset
2431 gimple_location (s),
kono
parents:
diff changeset
2432 is_store);
kono
parents:
diff changeset
2433 is_instrumented = true;
kono
parents:
diff changeset
2434 }
kono
parents:
diff changeset
2435
kono
parents:
diff changeset
2436 if (gimple_assign_load_p (s))
kono
parents:
diff changeset
2437 {
kono
parents:
diff changeset
2438 ref_expr = gimple_assign_rhs1 (s);
kono
parents:
diff changeset
2439 is_store = false;
kono
parents:
diff changeset
2440 instrument_derefs (iter, ref_expr,
kono
parents:
diff changeset
2441 gimple_location (s),
kono
parents:
diff changeset
2442 is_store);
kono
parents:
diff changeset
2443 is_instrumented = true;
kono
parents:
diff changeset
2444 }
kono
parents:
diff changeset
2445
kono
parents:
diff changeset
2446 if (is_instrumented)
kono
parents:
diff changeset
2447 gsi_next (iter);
kono
parents:
diff changeset
2448
kono
parents:
diff changeset
2449 return is_instrumented;
kono
parents:
diff changeset
2450 }
kono
parents:
diff changeset
2451
kono
parents:
diff changeset
2452 /* Instrument the function call pointed to by the iterator ITER, if it
kono
parents:
diff changeset
2453 is subject to instrumentation. At the moment, the only function
kono
parents:
diff changeset
2454 calls that are instrumented are some built-in functions that access
kono
parents:
diff changeset
2455 memory. Look at instrument_builtin_call to learn more.
kono
parents:
diff changeset
2456
kono
parents:
diff changeset
2457 Upon completion return TRUE iff *ITER was advanced to the statement
kono
parents:
diff changeset
2458 following the one it was originally pointing to. */
kono
parents:
diff changeset
2459
kono
parents:
diff changeset
2460 static bool
kono
parents:
diff changeset
2461 maybe_instrument_call (gimple_stmt_iterator *iter)
kono
parents:
diff changeset
2462 {
kono
parents:
diff changeset
2463 gimple *stmt = gsi_stmt (*iter);
kono
parents:
diff changeset
2464 bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
kono
parents:
diff changeset
2465
kono
parents:
diff changeset
2466 if (is_builtin && instrument_builtin_call (iter))
kono
parents:
diff changeset
2467 return true;
kono
parents:
diff changeset
2468
kono
parents:
diff changeset
2469 if (gimple_call_noreturn_p (stmt))
kono
parents:
diff changeset
2470 {
kono
parents:
diff changeset
2471 if (is_builtin)
kono
parents:
diff changeset
2472 {
kono
parents:
diff changeset
2473 tree callee = gimple_call_fndecl (stmt);
kono
parents:
diff changeset
2474 switch (DECL_FUNCTION_CODE (callee))
kono
parents:
diff changeset
2475 {
kono
parents:
diff changeset
2476 case BUILT_IN_UNREACHABLE:
kono
parents:
diff changeset
2477 case BUILT_IN_TRAP:
kono
parents:
diff changeset
2478 /* Don't instrument these. */
kono
parents:
diff changeset
2479 return false;
kono
parents:
diff changeset
2480 default:
kono
parents:
diff changeset
2481 break;
kono
parents:
diff changeset
2482 }
kono
parents:
diff changeset
2483 }
kono
parents:
diff changeset
2484 tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
kono
parents:
diff changeset
2485 gimple *g = gimple_build_call (decl, 0);
kono
parents:
diff changeset
2486 gimple_set_location (g, gimple_location (stmt));
kono
parents:
diff changeset
2487 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2488 }
kono
parents:
diff changeset
2489
kono
parents:
diff changeset
2490 bool instrumented = false;
kono
parents:
diff changeset
2491 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2492 {
kono
parents:
diff changeset
2493 tree ref_expr = gimple_call_lhs (stmt);
kono
parents:
diff changeset
2494 instrument_derefs (iter, ref_expr,
kono
parents:
diff changeset
2495 gimple_location (stmt),
kono
parents:
diff changeset
2496 /*is_store=*/true);
kono
parents:
diff changeset
2497
kono
parents:
diff changeset
2498 instrumented = true;
kono
parents:
diff changeset
2499 }
kono
parents:
diff changeset
2500
kono
parents:
diff changeset
2501 /* Walk through gimple_call arguments and check them id needed. */
kono
parents:
diff changeset
2502 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2503 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2504 {
kono
parents:
diff changeset
2505 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2506 /* If ARG is not a non-aggregate register variable, compiler in general
kono
parents:
diff changeset
2507 creates temporary for it and pass it as argument to gimple call.
kono
parents:
diff changeset
2508 But in some cases, e.g. when we pass by value a small structure that
kono
parents:
diff changeset
2509 fits to register, compiler can avoid extra overhead by pulling out
kono
parents:
diff changeset
2510 these temporaries. In this case, we should check the argument. */
kono
parents:
diff changeset
2511 if (!is_gimple_reg (arg) && !is_gimple_min_invariant (arg))
kono
parents:
diff changeset
2512 {
kono
parents:
diff changeset
2513 instrument_derefs (iter, arg,
kono
parents:
diff changeset
2514 gimple_location (stmt),
kono
parents:
diff changeset
2515 /*is_store=*/false);
kono
parents:
diff changeset
2516 instrumented = true;
kono
parents:
diff changeset
2517 }
kono
parents:
diff changeset
2518 }
kono
parents:
diff changeset
2519 if (instrumented)
kono
parents:
diff changeset
2520 gsi_next (iter);
kono
parents:
diff changeset
2521 return instrumented;
kono
parents:
diff changeset
2522 }
kono
parents:
diff changeset
2523
kono
parents:
diff changeset
2524 /* Walk each instruction of all basic block and instrument those that
kono
parents:
diff changeset
2525 represent memory references: loads, stores, or function calls.
kono
parents:
diff changeset
2526 In a given basic block, this function avoids instrumenting memory
kono
parents:
diff changeset
2527 references that have already been instrumented. */
kono
parents:
diff changeset
2528
kono
parents:
diff changeset
2529 static void
kono
parents:
diff changeset
2530 transform_statements (void)
kono
parents:
diff changeset
2531 {
kono
parents:
diff changeset
2532 basic_block bb, last_bb = NULL;
kono
parents:
diff changeset
2533 gimple_stmt_iterator i;
kono
parents:
diff changeset
2534 int saved_last_basic_block = last_basic_block_for_fn (cfun);
kono
parents:
diff changeset
2535
kono
parents:
diff changeset
2536 FOR_EACH_BB_FN (bb, cfun)
kono
parents:
diff changeset
2537 {
kono
parents:
diff changeset
2538 basic_block prev_bb = bb;
kono
parents:
diff changeset
2539
kono
parents:
diff changeset
2540 if (bb->index >= saved_last_basic_block) continue;
kono
parents:
diff changeset
2541
kono
parents:
diff changeset
2542 /* Flush the mem ref hash table, if current bb doesn't have
kono
parents:
diff changeset
2543 exactly one predecessor, or if that predecessor (skipping
kono
parents:
diff changeset
2544 over asan created basic blocks) isn't the last processed
kono
parents:
diff changeset
2545 basic block. Thus we effectively flush on extended basic
kono
parents:
diff changeset
2546 block boundaries. */
kono
parents:
diff changeset
2547 while (single_pred_p (prev_bb))
kono
parents:
diff changeset
2548 {
kono
parents:
diff changeset
2549 prev_bb = single_pred (prev_bb);
kono
parents:
diff changeset
2550 if (prev_bb->index < saved_last_basic_block)
kono
parents:
diff changeset
2551 break;
kono
parents:
diff changeset
2552 }
kono
parents:
diff changeset
2553 if (prev_bb != last_bb)
kono
parents:
diff changeset
2554 empty_mem_ref_hash_table ();
kono
parents:
diff changeset
2555 last_bb = bb;
kono
parents:
diff changeset
2556
kono
parents:
diff changeset
2557 for (i = gsi_start_bb (bb); !gsi_end_p (i);)
kono
parents:
diff changeset
2558 {
kono
parents:
diff changeset
2559 gimple *s = gsi_stmt (i);
kono
parents:
diff changeset
2560
kono
parents:
diff changeset
2561 if (has_stmt_been_instrumented_p (s))
kono
parents:
diff changeset
2562 gsi_next (&i);
kono
parents:
diff changeset
2563 else if (gimple_assign_single_p (s)
kono
parents:
diff changeset
2564 && !gimple_clobber_p (s)
kono
parents:
diff changeset
2565 && maybe_instrument_assignment (&i))
kono
parents:
diff changeset
2566 /* Nothing to do as maybe_instrument_assignment advanced
kono
parents:
diff changeset
2567 the iterator I. */;
kono
parents:
diff changeset
2568 else if (is_gimple_call (s) && maybe_instrument_call (&i))
kono
parents:
diff changeset
2569 /* Nothing to do as maybe_instrument_call
kono
parents:
diff changeset
2570 advanced the iterator I. */;
kono
parents:
diff changeset
2571 else
kono
parents:
diff changeset
2572 {
kono
parents:
diff changeset
2573 /* No instrumentation happened.
kono
parents:
diff changeset
2574
kono
parents:
diff changeset
2575 If the current instruction is a function call that
kono
parents:
diff changeset
2576 might free something, let's forget about the memory
kono
parents:
diff changeset
2577 references that got instrumented. Otherwise we might
kono
parents:
diff changeset
2578 miss some instrumentation opportunities. Do the same
kono
parents:
diff changeset
2579 for a ASAN_MARK poisoning internal function. */
kono
parents:
diff changeset
2580 if (is_gimple_call (s)
kono
parents:
diff changeset
2581 && (!nonfreeing_call_p (s)
kono
parents:
diff changeset
2582 || asan_mark_p (s, ASAN_MARK_POISON)))
kono
parents:
diff changeset
2583 empty_mem_ref_hash_table ();
kono
parents:
diff changeset
2584
kono
parents:
diff changeset
2585 gsi_next (&i);
kono
parents:
diff changeset
2586 }
kono
parents:
diff changeset
2587 }
kono
parents:
diff changeset
2588 }
kono
parents:
diff changeset
2589 free_mem_ref_resources ();
kono
parents:
diff changeset
2590 }
kono
parents:
diff changeset
2591
kono
parents:
diff changeset
2592 /* Build
kono
parents:
diff changeset
2593 __asan_before_dynamic_init (module_name)
kono
parents:
diff changeset
2594 or
kono
parents:
diff changeset
2595 __asan_after_dynamic_init ()
kono
parents:
diff changeset
2596 call. */
kono
parents:
diff changeset
2597
kono
parents:
diff changeset
2598 tree
kono
parents:
diff changeset
2599 asan_dynamic_init_call (bool after_p)
kono
parents:
diff changeset
2600 {
kono
parents:
diff changeset
2601 if (shadow_ptr_types[0] == NULL_TREE)
kono
parents:
diff changeset
2602 asan_init_shadow_ptr_types ();
kono
parents:
diff changeset
2603
kono
parents:
diff changeset
2604 tree fn = builtin_decl_implicit (after_p
kono
parents:
diff changeset
2605 ? BUILT_IN_ASAN_AFTER_DYNAMIC_INIT
kono
parents:
diff changeset
2606 : BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT);
kono
parents:
diff changeset
2607 tree module_name_cst = NULL_TREE;
kono
parents:
diff changeset
2608 if (!after_p)
kono
parents:
diff changeset
2609 {
kono
parents:
diff changeset
2610 pretty_printer module_name_pp;
kono
parents:
diff changeset
2611 pp_string (&module_name_pp, main_input_filename);
kono
parents:
diff changeset
2612
kono
parents:
diff changeset
2613 module_name_cst = asan_pp_string (&module_name_pp);
kono
parents:
diff changeset
2614 module_name_cst = fold_convert (const_ptr_type_node,
kono
parents:
diff changeset
2615 module_name_cst);
kono
parents:
diff changeset
2616 }
kono
parents:
diff changeset
2617
kono
parents:
diff changeset
2618 return build_call_expr (fn, after_p ? 0 : 1, module_name_cst);
kono
parents:
diff changeset
2619 }
kono
parents:
diff changeset
2620
kono
parents:
diff changeset
2621 /* Build
kono
parents:
diff changeset
2622 struct __asan_global
kono
parents:
diff changeset
2623 {
kono
parents:
diff changeset
2624 const void *__beg;
kono
parents:
diff changeset
2625 uptr __size;
kono
parents:
diff changeset
2626 uptr __size_with_redzone;
kono
parents:
diff changeset
2627 const void *__name;
kono
parents:
diff changeset
2628 const void *__module_name;
kono
parents:
diff changeset
2629 uptr __has_dynamic_init;
kono
parents:
diff changeset
2630 __asan_global_source_location *__location;
kono
parents:
diff changeset
2631 char *__odr_indicator;
kono
parents:
diff changeset
2632 } type. */
kono
parents:
diff changeset
2633
kono
parents:
diff changeset
2634 static tree
kono
parents:
diff changeset
2635 asan_global_struct (void)
kono
parents:
diff changeset
2636 {
kono
parents:
diff changeset
2637 static const char *field_names[]
kono
parents:
diff changeset
2638 = { "__beg", "__size", "__size_with_redzone",
kono
parents:
diff changeset
2639 "__name", "__module_name", "__has_dynamic_init", "__location",
kono
parents:
diff changeset
2640 "__odr_indicator" };
kono
parents:
diff changeset
2641 tree fields[ARRAY_SIZE (field_names)], ret;
kono
parents:
diff changeset
2642 unsigned i;
kono
parents:
diff changeset
2643
kono
parents:
diff changeset
2644 ret = make_node (RECORD_TYPE);
kono
parents:
diff changeset
2645 for (i = 0; i < ARRAY_SIZE (field_names); i++)
kono
parents:
diff changeset
2646 {
kono
parents:
diff changeset
2647 fields[i]
kono
parents:
diff changeset
2648 = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
kono
parents:
diff changeset
2649 get_identifier (field_names[i]),
kono
parents:
diff changeset
2650 (i == 0 || i == 3) ? const_ptr_type_node
kono
parents:
diff changeset
2651 : pointer_sized_int_node);
kono
parents:
diff changeset
2652 DECL_CONTEXT (fields[i]) = ret;
kono
parents:
diff changeset
2653 if (i)
kono
parents:
diff changeset
2654 DECL_CHAIN (fields[i - 1]) = fields[i];
kono
parents:
diff changeset
2655 }
kono
parents:
diff changeset
2656 tree type_decl = build_decl (input_location, TYPE_DECL,
kono
parents:
diff changeset
2657 get_identifier ("__asan_global"), ret);
kono
parents:
diff changeset
2658 DECL_IGNORED_P (type_decl) = 1;
kono
parents:
diff changeset
2659 DECL_ARTIFICIAL (type_decl) = 1;
kono
parents:
diff changeset
2660 TYPE_FIELDS (ret) = fields[0];
kono
parents:
diff changeset
2661 TYPE_NAME (ret) = type_decl;
kono
parents:
diff changeset
2662 TYPE_STUB_DECL (ret) = type_decl;
kono
parents:
diff changeset
2663 layout_type (ret);
kono
parents:
diff changeset
2664 return ret;
kono
parents:
diff changeset
2665 }
kono
parents:
diff changeset
2666
kono
parents:
diff changeset
2667 /* Create and return odr indicator symbol for DECL.
kono
parents:
diff changeset
2668 TYPE is __asan_global struct type as returned by asan_global_struct. */
kono
parents:
diff changeset
2669
kono
parents:
diff changeset
2670 static tree
kono
parents:
diff changeset
2671 create_odr_indicator (tree decl, tree type)
kono
parents:
diff changeset
2672 {
kono
parents:
diff changeset
2673 char *name;
kono
parents:
diff changeset
2674 tree uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
kono
parents:
diff changeset
2675 tree decl_name
kono
parents:
diff changeset
2676 = (HAS_DECL_ASSEMBLER_NAME_P (decl) ? DECL_ASSEMBLER_NAME (decl)
kono
parents:
diff changeset
2677 : DECL_NAME (decl));
kono
parents:
diff changeset
2678 /* DECL_NAME theoretically might be NULL. Bail out with 0 in this case. */
kono
parents:
diff changeset
2679 if (decl_name == NULL_TREE)
kono
parents:
diff changeset
2680 return build_int_cst (uptr, 0);
kono
parents:
diff changeset
2681 const char *dname = IDENTIFIER_POINTER (decl_name);
kono
parents:
diff changeset
2682 if (HAS_DECL_ASSEMBLER_NAME_P (decl))
kono
parents:
diff changeset
2683 dname = targetm.strip_name_encoding (dname);
kono
parents:
diff changeset
2684 size_t len = strlen (dname) + sizeof ("__odr_asan_");
kono
parents:
diff changeset
2685 name = XALLOCAVEC (char, len);
kono
parents:
diff changeset
2686 snprintf (name, len, "__odr_asan_%s", dname);
kono
parents:
diff changeset
2687 #ifndef NO_DOT_IN_LABEL
kono
parents:
diff changeset
2688 name[sizeof ("__odr_asan") - 1] = '.';
kono
parents:
diff changeset
2689 #elif !defined(NO_DOLLAR_IN_LABEL)
kono
parents:
diff changeset
2690 name[sizeof ("__odr_asan") - 1] = '$';
kono
parents:
diff changeset
2691 #endif
kono
parents:
diff changeset
2692 tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (name),
kono
parents:
diff changeset
2693 char_type_node);
kono
parents:
diff changeset
2694 TREE_ADDRESSABLE (var) = 1;
kono
parents:
diff changeset
2695 TREE_READONLY (var) = 0;
kono
parents:
diff changeset
2696 TREE_THIS_VOLATILE (var) = 1;
kono
parents:
diff changeset
2697 DECL_GIMPLE_REG_P (var) = 0;
kono
parents:
diff changeset
2698 DECL_ARTIFICIAL (var) = 1;
kono
parents:
diff changeset
2699 DECL_IGNORED_P (var) = 1;
kono
parents:
diff changeset
2700 TREE_STATIC (var) = 1;
kono
parents:
diff changeset
2701 TREE_PUBLIC (var) = 1;
kono
parents:
diff changeset
2702 DECL_VISIBILITY (var) = DECL_VISIBILITY (decl);
kono
parents:
diff changeset
2703 DECL_VISIBILITY_SPECIFIED (var) = DECL_VISIBILITY_SPECIFIED (decl);
kono
parents:
diff changeset
2704
kono
parents:
diff changeset
2705 TREE_USED (var) = 1;
kono
parents:
diff changeset
2706 tree ctor = build_constructor_va (TREE_TYPE (var), 1, NULL_TREE,
kono
parents:
diff changeset
2707 build_int_cst (unsigned_type_node, 0));
kono
parents:
diff changeset
2708 TREE_CONSTANT (ctor) = 1;
kono
parents:
diff changeset
2709 TREE_STATIC (ctor) = 1;
kono
parents:
diff changeset
2710 DECL_INITIAL (var) = ctor;
kono
parents:
diff changeset
2711 DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("asan odr indicator"),
kono
parents:
diff changeset
2712 NULL, DECL_ATTRIBUTES (var));
kono
parents:
diff changeset
2713 make_decl_rtl (var);
kono
parents:
diff changeset
2714 varpool_node::finalize_decl (var);
kono
parents:
diff changeset
2715 return fold_convert (uptr, build_fold_addr_expr (var));
kono
parents:
diff changeset
2716 }
kono
parents:
diff changeset
2717
kono
parents:
diff changeset
2718 /* Return true if DECL, a global var, might be overridden and needs
kono
parents:
diff changeset
2719 an additional odr indicator symbol. */
kono
parents:
diff changeset
2720
kono
parents:
diff changeset
2721 static bool
kono
parents:
diff changeset
2722 asan_needs_odr_indicator_p (tree decl)
kono
parents:
diff changeset
2723 {
kono
parents:
diff changeset
2724 /* Don't emit ODR indicators for kernel because:
kono
parents:
diff changeset
2725 a) Kernel is written in C thus doesn't need ODR indicators.
kono
parents:
diff changeset
2726 b) Some kernel code may have assumptions about symbols containing specific
kono
parents:
diff changeset
2727 patterns in their names. Since ODR indicators contain original names
kono
parents:
diff changeset
2728 of symbols they are emitted for, these assumptions would be broken for
kono
parents:
diff changeset
2729 ODR indicator symbols. */
kono
parents:
diff changeset
2730 return (!(flag_sanitize & SANITIZE_KERNEL_ADDRESS)
kono
parents:
diff changeset
2731 && !DECL_ARTIFICIAL (decl)
kono
parents:
diff changeset
2732 && !DECL_WEAK (decl)
kono
parents:
diff changeset
2733 && TREE_PUBLIC (decl));
kono
parents:
diff changeset
2734 }
kono
parents:
diff changeset
2735
kono
parents:
diff changeset
2736 /* Append description of a single global DECL into vector V.
kono
parents:
diff changeset
2737 TYPE is __asan_global struct type as returned by asan_global_struct. */
kono
parents:
diff changeset
2738
kono
parents:
diff changeset
2739 static void
kono
parents:
diff changeset
2740 asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
kono
parents:
diff changeset
2741 {
kono
parents:
diff changeset
2742 tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
kono
parents:
diff changeset
2743 unsigned HOST_WIDE_INT size;
kono
parents:
diff changeset
2744 tree str_cst, module_name_cst, refdecl = decl;
kono
parents:
diff changeset
2745 vec<constructor_elt, va_gc> *vinner = NULL;
kono
parents:
diff changeset
2746
kono
parents:
diff changeset
2747 pretty_printer asan_pp, module_name_pp;
kono
parents:
diff changeset
2748
kono
parents:
diff changeset
2749 if (DECL_NAME (decl))
kono
parents:
diff changeset
2750 pp_tree_identifier (&asan_pp, DECL_NAME (decl));
kono
parents:
diff changeset
2751 else
kono
parents:
diff changeset
2752 pp_string (&asan_pp, "<unknown>");
kono
parents:
diff changeset
2753 str_cst = asan_pp_string (&asan_pp);
kono
parents:
diff changeset
2754
kono
parents:
diff changeset
2755 pp_string (&module_name_pp, main_input_filename);
kono
parents:
diff changeset
2756 module_name_cst = asan_pp_string (&module_name_pp);
kono
parents:
diff changeset
2757
kono
parents:
diff changeset
2758 if (asan_needs_local_alias (decl))
kono
parents:
diff changeset
2759 {
kono
parents:
diff changeset
2760 char buf[20];
kono
parents:
diff changeset
2761 ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", vec_safe_length (v) + 1);
kono
parents:
diff changeset
2762 refdecl = build_decl (DECL_SOURCE_LOCATION (decl),
kono
parents:
diff changeset
2763 VAR_DECL, get_identifier (buf), TREE_TYPE (decl));
kono
parents:
diff changeset
2764 TREE_ADDRESSABLE (refdecl) = TREE_ADDRESSABLE (decl);
kono
parents:
diff changeset
2765 TREE_READONLY (refdecl) = TREE_READONLY (decl);
kono
parents:
diff changeset
2766 TREE_THIS_VOLATILE (refdecl) = TREE_THIS_VOLATILE (decl);
kono
parents:
diff changeset
2767 DECL_GIMPLE_REG_P (refdecl) = DECL_GIMPLE_REG_P (decl);
kono
parents:
diff changeset
2768 DECL_ARTIFICIAL (refdecl) = DECL_ARTIFICIAL (decl);
kono
parents:
diff changeset
2769 DECL_IGNORED_P (refdecl) = DECL_IGNORED_P (decl);
kono
parents:
diff changeset
2770 TREE_STATIC (refdecl) = 1;
kono
parents:
diff changeset
2771 TREE_PUBLIC (refdecl) = 0;
kono
parents:
diff changeset
2772 TREE_USED (refdecl) = 1;
kono
parents:
diff changeset
2773 assemble_alias (refdecl, DECL_ASSEMBLER_NAME (decl));
kono
parents:
diff changeset
2774 }
kono
parents:
diff changeset
2775
kono
parents:
diff changeset
2776 tree odr_indicator_ptr
kono
parents:
diff changeset
2777 = (asan_needs_odr_indicator_p (decl) ? create_odr_indicator (decl, type)
kono
parents:
diff changeset
2778 : build_int_cst (uptr, 0));
kono
parents:
diff changeset
2779 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
kono
parents:
diff changeset
2780 fold_convert (const_ptr_type_node,
kono
parents:
diff changeset
2781 build_fold_addr_expr (refdecl)));
kono
parents:
diff changeset
2782 size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
kono
parents:
diff changeset
2783 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
kono
parents:
diff changeset
2784 size += asan_red_zone_size (size);
kono
parents:
diff changeset
2785 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
kono
parents:
diff changeset
2786 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
kono
parents:
diff changeset
2787 fold_convert (const_ptr_type_node, str_cst));
kono
parents:
diff changeset
2788 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
kono
parents:
diff changeset
2789 fold_convert (const_ptr_type_node, module_name_cst));
kono
parents:
diff changeset
2790 varpool_node *vnode = varpool_node::get (decl);
kono
parents:
diff changeset
2791 int has_dynamic_init = 0;
kono
parents:
diff changeset
2792 /* FIXME: Enable initialization order fiasco detection in LTO mode once
kono
parents:
diff changeset
2793 proper fix for PR 79061 will be applied. */
kono
parents:
diff changeset
2794 if (!in_lto_p)
kono
parents:
diff changeset
2795 has_dynamic_init = vnode ? vnode->dynamically_initialized : 0;
kono
parents:
diff changeset
2796 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
kono
parents:
diff changeset
2797 build_int_cst (uptr, has_dynamic_init));
kono
parents:
diff changeset
2798 tree locptr = NULL_TREE;
kono
parents:
diff changeset
2799 location_t loc = DECL_SOURCE_LOCATION (decl);
kono
parents:
diff changeset
2800 expanded_location xloc = expand_location (loc);
kono
parents:
diff changeset
2801 if (xloc.file != NULL)
kono
parents:
diff changeset
2802 {
kono
parents:
diff changeset
2803 static int lasanloccnt = 0;
kono
parents:
diff changeset
2804 char buf[25];
kono
parents:
diff changeset
2805 ASM_GENERATE_INTERNAL_LABEL (buf, "LASANLOC", ++lasanloccnt);
kono
parents:
diff changeset
2806 tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
kono
parents:
diff changeset
2807 ubsan_get_source_location_type ());
kono
parents:
diff changeset
2808 TREE_STATIC (var) = 1;
kono
parents:
diff changeset
2809 TREE_PUBLIC (var) = 0;
kono
parents:
diff changeset
2810 DECL_ARTIFICIAL (var) = 1;
kono
parents:
diff changeset
2811 DECL_IGNORED_P (var) = 1;
kono
parents:
diff changeset
2812 pretty_printer filename_pp;
kono
parents:
diff changeset
2813 pp_string (&filename_pp, xloc.file);
kono
parents:
diff changeset
2814 tree str = asan_pp_string (&filename_pp);
kono
parents:
diff changeset
2815 tree ctor = build_constructor_va (TREE_TYPE (var), 3,
kono
parents:
diff changeset
2816 NULL_TREE, str, NULL_TREE,
kono
parents:
diff changeset
2817 build_int_cst (unsigned_type_node,
kono
parents:
diff changeset
2818 xloc.line), NULL_TREE,
kono
parents:
diff changeset
2819 build_int_cst (unsigned_type_node,
kono
parents:
diff changeset
2820 xloc.column));
kono
parents:
diff changeset
2821 TREE_CONSTANT (ctor) = 1;
kono
parents:
diff changeset
2822 TREE_STATIC (ctor) = 1;
kono
parents:
diff changeset
2823 DECL_INITIAL (var) = ctor;
kono
parents:
diff changeset
2824 varpool_node::finalize_decl (var);
kono
parents:
diff changeset
2825 locptr = fold_convert (uptr, build_fold_addr_expr (var));
kono
parents:
diff changeset
2826 }
kono
parents:
diff changeset
2827 else
kono
parents:
diff changeset
2828 locptr = build_int_cst (uptr, 0);
kono
parents:
diff changeset
2829 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, locptr);
kono
parents:
diff changeset
2830 CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, odr_indicator_ptr);
kono
parents:
diff changeset
2831 init = build_constructor (type, vinner);
kono
parents:
diff changeset
2832 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
kono
parents:
diff changeset
2833 }
kono
parents:
diff changeset
2834
kono
parents:
diff changeset
2835 /* Initialize sanitizer.def builtins if the FE hasn't initialized them. */
kono
parents:
diff changeset
2836 void
kono
parents:
diff changeset
2837 initialize_sanitizer_builtins (void)
kono
parents:
diff changeset
2838 {
kono
parents:
diff changeset
2839 tree decl;
kono
parents:
diff changeset
2840
kono
parents:
diff changeset
2841 if (builtin_decl_implicit_p (BUILT_IN_ASAN_INIT))
kono
parents:
diff changeset
2842 return;
kono
parents:
diff changeset
2843
kono
parents:
diff changeset
2844 tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE);
kono
parents:
diff changeset
2845 tree BT_FN_VOID_PTR
kono
parents:
diff changeset
2846 = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
kono
parents:
diff changeset
2847 tree BT_FN_VOID_CONST_PTR
kono
parents:
diff changeset
2848 = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE);
kono
parents:
diff changeset
2849 tree BT_FN_VOID_PTR_PTR
kono
parents:
diff changeset
2850 = build_function_type_list (void_type_node, ptr_type_node,
kono
parents:
diff changeset
2851 ptr_type_node, NULL_TREE);
kono
parents:
diff changeset
2852 tree BT_FN_VOID_PTR_PTR_PTR
kono
parents:
diff changeset
2853 = build_function_type_list (void_type_node, ptr_type_node,
kono
parents:
diff changeset
2854 ptr_type_node, ptr_type_node, NULL_TREE);
kono
parents:
diff changeset
2855 tree BT_FN_VOID_PTR_PTRMODE
kono
parents:
diff changeset
2856 = build_function_type_list (void_type_node, ptr_type_node,
kono
parents:
diff changeset
2857 pointer_sized_int_node, NULL_TREE);
kono
parents:
diff changeset
2858 tree BT_FN_VOID_INT
kono
parents:
diff changeset
2859 = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
kono
parents:
diff changeset
2860 tree BT_FN_SIZE_CONST_PTR_INT
kono
parents:
diff changeset
2861 = build_function_type_list (size_type_node, const_ptr_type_node,
kono
parents:
diff changeset
2862 integer_type_node, NULL_TREE);
kono
parents:
diff changeset
2863
kono
parents:
diff changeset
2864 tree BT_FN_VOID_UINT8_UINT8
kono
parents:
diff changeset
2865 = build_function_type_list (void_type_node, unsigned_char_type_node,
kono
parents:
diff changeset
2866 unsigned_char_type_node, NULL_TREE);
kono
parents:
diff changeset
2867 tree BT_FN_VOID_UINT16_UINT16
kono
parents:
diff changeset
2868 = build_function_type_list (void_type_node, uint16_type_node,
kono
parents:
diff changeset
2869 uint16_type_node, NULL_TREE);
kono
parents:
diff changeset
2870 tree BT_FN_VOID_UINT32_UINT32
kono
parents:
diff changeset
2871 = build_function_type_list (void_type_node, uint32_type_node,
kono
parents:
diff changeset
2872 uint32_type_node, NULL_TREE);
kono
parents:
diff changeset
2873 tree BT_FN_VOID_UINT64_UINT64
kono
parents:
diff changeset
2874 = build_function_type_list (void_type_node, uint64_type_node,
kono
parents:
diff changeset
2875 uint64_type_node, NULL_TREE);
kono
parents:
diff changeset
2876 tree BT_FN_VOID_FLOAT_FLOAT
kono
parents:
diff changeset
2877 = build_function_type_list (void_type_node, float_type_node,
kono
parents:
diff changeset
2878 float_type_node, NULL_TREE);
kono
parents:
diff changeset
2879 tree BT_FN_VOID_DOUBLE_DOUBLE
kono
parents:
diff changeset
2880 = build_function_type_list (void_type_node, double_type_node,
kono
parents:
diff changeset
2881 double_type_node, NULL_TREE);
kono
parents:
diff changeset
2882 tree BT_FN_VOID_UINT64_PTR
kono
parents:
diff changeset
2883 = build_function_type_list (void_type_node, uint64_type_node,
kono
parents:
diff changeset
2884 ptr_type_node, NULL_TREE);
kono
parents:
diff changeset
2885
kono
parents:
diff changeset
2886 tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
kono
parents:
diff changeset
2887 tree BT_FN_IX_CONST_VPTR_INT[5];
kono
parents:
diff changeset
2888 tree BT_FN_IX_VPTR_IX_INT[5];
kono
parents:
diff changeset
2889 tree BT_FN_VOID_VPTR_IX_INT[5];
kono
parents:
diff changeset
2890 tree vptr
kono
parents:
diff changeset
2891 = build_pointer_type (build_qualified_type (void_type_node,
kono
parents:
diff changeset
2892 TYPE_QUAL_VOLATILE));
kono
parents:
diff changeset
2893 tree cvptr
kono
parents:
diff changeset
2894 = build_pointer_type (build_qualified_type (void_type_node,
kono
parents:
diff changeset
2895 TYPE_QUAL_VOLATILE
kono
parents:
diff changeset
2896 |TYPE_QUAL_CONST));
kono
parents:
diff changeset
2897 tree boolt
kono
parents:
diff changeset
2898 = lang_hooks.types.type_for_size (BOOL_TYPE_SIZE, 1);
kono
parents:
diff changeset
2899 int i;
kono
parents:
diff changeset
2900 for (i = 0; i < 5; i++)
kono
parents:
diff changeset
2901 {
kono
parents:
diff changeset
2902 tree ix = build_nonstandard_integer_type (BITS_PER_UNIT * (1 << i), 1);
kono
parents:
diff changeset
2903 BT_FN_BOOL_VPTR_PTR_IX_INT_INT[i]
kono
parents:
diff changeset
2904 = build_function_type_list (boolt, vptr, ptr_type_node, ix,
kono
parents:
diff changeset
2905 integer_type_node, integer_type_node,
kono
parents:
diff changeset
2906 NULL_TREE);
kono
parents:
diff changeset
2907 BT_FN_IX_CONST_VPTR_INT[i]
kono
parents:
diff changeset
2908 = build_function_type_list (ix, cvptr, integer_type_node, NULL_TREE);
kono
parents:
diff changeset
2909 BT_FN_IX_VPTR_IX_INT[i]
kono
parents:
diff changeset
2910 = build_function_type_list (ix, vptr, ix, integer_type_node,
kono
parents:
diff changeset
2911 NULL_TREE);
kono
parents:
diff changeset
2912 BT_FN_VOID_VPTR_IX_INT[i]
kono
parents:
diff changeset
2913 = build_function_type_list (void_type_node, vptr, ix,
kono
parents:
diff changeset
2914 integer_type_node, NULL_TREE);
kono
parents:
diff changeset
2915 }
kono
parents:
diff changeset
2916 #define BT_FN_BOOL_VPTR_PTR_I1_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[0]
kono
parents:
diff changeset
2917 #define BT_FN_I1_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[0]
kono
parents:
diff changeset
2918 #define BT_FN_I1_VPTR_I1_INT BT_FN_IX_VPTR_IX_INT[0]
kono
parents:
diff changeset
2919 #define BT_FN_VOID_VPTR_I1_INT BT_FN_VOID_VPTR_IX_INT[0]
kono
parents:
diff changeset
2920 #define BT_FN_BOOL_VPTR_PTR_I2_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[1]
kono
parents:
diff changeset
2921 #define BT_FN_I2_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[1]
kono
parents:
diff changeset
2922 #define BT_FN_I2_VPTR_I2_INT BT_FN_IX_VPTR_IX_INT[1]
kono
parents:
diff changeset
2923 #define BT_FN_VOID_VPTR_I2_INT BT_FN_VOID_VPTR_IX_INT[1]
kono
parents:
diff changeset
2924 #define BT_FN_BOOL_VPTR_PTR_I4_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[2]
kono
parents:
diff changeset
2925 #define BT_FN_I4_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[2]
kono
parents:
diff changeset
2926 #define BT_FN_I4_VPTR_I4_INT BT_FN_IX_VPTR_IX_INT[2]
kono
parents:
diff changeset
2927 #define BT_FN_VOID_VPTR_I4_INT BT_FN_VOID_VPTR_IX_INT[2]
kono
parents:
diff changeset
2928 #define BT_FN_BOOL_VPTR_PTR_I8_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[3]
kono
parents:
diff changeset
2929 #define BT_FN_I8_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[3]
kono
parents:
diff changeset
2930 #define BT_FN_I8_VPTR_I8_INT BT_FN_IX_VPTR_IX_INT[3]
kono
parents:
diff changeset
2931 #define BT_FN_VOID_VPTR_I8_INT BT_FN_VOID_VPTR_IX_INT[3]
kono
parents:
diff changeset
2932 #define BT_FN_BOOL_VPTR_PTR_I16_INT_INT BT_FN_BOOL_VPTR_PTR_IX_INT_INT[4]
kono
parents:
diff changeset
2933 #define BT_FN_I16_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[4]
kono
parents:
diff changeset
2934 #define BT_FN_I16_VPTR_I16_INT BT_FN_IX_VPTR_IX_INT[4]
kono
parents:
diff changeset
2935 #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
kono
parents:
diff changeset
2936 #undef ATTR_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2937 #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
kono
parents:
diff changeset
2938 #undef ATTR_TMPURE_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2939 #define ATTR_TMPURE_NOTHROW_LEAF_LIST ECF_TM_PURE | ATTR_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2940 #undef ATTR_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2941 #define ATTR_NORETURN_NOTHROW_LEAF_LIST ECF_NORETURN | ATTR_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2942 #undef ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2943 #define ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST \
kono
parents:
diff changeset
2944 ECF_CONST | ATTR_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2945 #undef ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2946 #define ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST \
kono
parents:
diff changeset
2947 ECF_TM_PURE | ATTR_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2948 #undef ATTR_COLD_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2949 #define ATTR_COLD_NOTHROW_LEAF_LIST \
kono
parents:
diff changeset
2950 /* ECF_COLD missing */ ATTR_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2951 #undef ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2952 #define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
kono
parents:
diff changeset
2953 /* ECF_COLD missing */ ATTR_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2954 #undef ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2955 #define ATTR_COLD_CONST_NORETURN_NOTHROW_LEAF_LIST \
kono
parents:
diff changeset
2956 /* ECF_COLD missing */ ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2957 #undef ATTR_PURE_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2958 #define ATTR_PURE_NOTHROW_LEAF_LIST ECF_PURE | ATTR_NOTHROW_LEAF_LIST
kono
parents:
diff changeset
2959 #undef DEF_BUILTIN_STUB
kono
parents:
diff changeset
2960 #define DEF_BUILTIN_STUB(ENUM, NAME)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2961 #undef DEF_SANITIZER_BUILTIN_1
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2962 #define DEF_SANITIZER_BUILTIN_1(ENUM, NAME, TYPE, ATTRS) \
111
kono
parents:
diff changeset
2963 do { \
kono
parents:
diff changeset
2964 decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM, \
kono
parents:
diff changeset
2965 BUILT_IN_NORMAL, NAME, NULL_TREE); \
kono
parents:
diff changeset
2966 set_call_expr_flags (decl, ATTRS); \
kono
parents:
diff changeset
2967 set_builtin_decl (ENUM, decl, true); \
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2968 } while (0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2969 #undef DEF_SANITIZER_BUILTIN
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2970 #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2971 DEF_SANITIZER_BUILTIN_1 (ENUM, NAME, TYPE, ATTRS);
111
kono
parents:
diff changeset
2972
kono
parents:
diff changeset
2973 #include "sanitizer.def"
kono
parents:
diff changeset
2974
kono
parents:
diff changeset
2975 /* -fsanitize=object-size uses __builtin_object_size, but that might
kono
parents:
diff changeset
2976 not be available for e.g. Fortran at this point. We use
kono
parents:
diff changeset
2977 DEF_SANITIZER_BUILTIN here only as a convenience macro. */
kono
parents:
diff changeset
2978 if ((flag_sanitize & SANITIZE_OBJECT_SIZE)
kono
parents:
diff changeset
2979 && !builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2980 DEF_SANITIZER_BUILTIN_1 (BUILT_IN_OBJECT_SIZE, "object_size",
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2981 BT_FN_SIZE_CONST_PTR_INT,
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2982 ATTR_PURE_NOTHROW_LEAF_LIST);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2983
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2984 #undef DEF_SANITIZER_BUILTIN_1
111
kono
parents:
diff changeset
2985 #undef DEF_SANITIZER_BUILTIN
kono
parents:
diff changeset
2986 #undef DEF_BUILTIN_STUB
kono
parents:
diff changeset
2987 }
kono
parents:
diff changeset
2988
kono
parents:
diff changeset
2989 /* Called via htab_traverse. Count number of emitted
kono
parents:
diff changeset
2990 STRING_CSTs in the constant hash table. */
kono
parents:
diff changeset
2991
kono
parents:
diff changeset
2992 int
kono
parents:
diff changeset
2993 count_string_csts (constant_descriptor_tree **slot,
kono
parents:
diff changeset
2994 unsigned HOST_WIDE_INT *data)
kono
parents:
diff changeset
2995 {
kono
parents:
diff changeset
2996 struct constant_descriptor_tree *desc = *slot;
kono
parents:
diff changeset
2997 if (TREE_CODE (desc->value) == STRING_CST
kono
parents:
diff changeset
2998 && TREE_ASM_WRITTEN (desc->value)
kono
parents:
diff changeset
2999 && asan_protect_global (desc->value))
kono
parents:
diff changeset
3000 ++*data;
kono
parents:
diff changeset
3001 return 1;
kono
parents:
diff changeset
3002 }
kono
parents:
diff changeset
3003
kono
parents:
diff changeset
3004 /* Helper structure to pass two parameters to
kono
parents:
diff changeset
3005 add_string_csts. */
kono
parents:
diff changeset
3006
kono
parents:
diff changeset
3007 struct asan_add_string_csts_data
kono
parents:
diff changeset
3008 {
kono
parents:
diff changeset
3009 tree type;
kono
parents:
diff changeset
3010 vec<constructor_elt, va_gc> *v;
kono
parents:
diff changeset
3011 };
kono
parents:
diff changeset
3012
kono
parents:
diff changeset
3013 /* Called via hash_table::traverse. Call asan_add_global
kono
parents:
diff changeset
3014 on emitted STRING_CSTs from the constant hash table. */
kono
parents:
diff changeset
3015
kono
parents:
diff changeset
3016 int
kono
parents:
diff changeset
3017 add_string_csts (constant_descriptor_tree **slot,
kono
parents:
diff changeset
3018 asan_add_string_csts_data *aascd)
kono
parents:
diff changeset
3019 {
kono
parents:
diff changeset
3020 struct constant_descriptor_tree *desc = *slot;
kono
parents:
diff changeset
3021 if (TREE_CODE (desc->value) == STRING_CST
kono
parents:
diff changeset
3022 && TREE_ASM_WRITTEN (desc->value)
kono
parents:
diff changeset
3023 && asan_protect_global (desc->value))
kono
parents:
diff changeset
3024 {
kono
parents:
diff changeset
3025 asan_add_global (SYMBOL_REF_DECL (XEXP (desc->rtl, 0)),
kono
parents:
diff changeset
3026 aascd->type, aascd->v);
kono
parents:
diff changeset
3027 }
kono
parents:
diff changeset
3028 return 1;
kono
parents:
diff changeset
3029 }
kono
parents:
diff changeset
3030
kono
parents:
diff changeset
3031 /* Needs to be GTY(()), because cgraph_build_static_cdtor may
kono
parents:
diff changeset
3032 invoke ggc_collect. */
kono
parents:
diff changeset
3033 static GTY(()) tree asan_ctor_statements;
kono
parents:
diff changeset
3034
kono
parents:
diff changeset
3035 /* Module-level instrumentation.
kono
parents:
diff changeset
3036 - Insert __asan_init_vN() into the list of CTORs.
kono
parents:
diff changeset
3037 - TODO: insert redzones around globals.
kono
parents:
diff changeset
3038 */
kono
parents:
diff changeset
3039
kono
parents:
diff changeset
3040 void
kono
parents:
diff changeset
3041 asan_finish_file (void)
kono
parents:
diff changeset
3042 {
kono
parents:
diff changeset
3043 varpool_node *vnode;
kono
parents:
diff changeset
3044 unsigned HOST_WIDE_INT gcount = 0;
kono
parents:
diff changeset
3045
kono
parents:
diff changeset
3046 if (shadow_ptr_types[0] == NULL_TREE)
kono
parents:
diff changeset
3047 asan_init_shadow_ptr_types ();
kono
parents:
diff changeset
3048 /* Avoid instrumenting code in the asan ctors/dtors.
kono
parents:
diff changeset
3049 We don't need to insert padding after the description strings,
kono
parents:
diff changeset
3050 nor after .LASAN* array. */
kono
parents:
diff changeset
3051 flag_sanitize &= ~SANITIZE_ADDRESS;
kono
parents:
diff changeset
3052
kono
parents:
diff changeset
3053 /* For user-space we want asan constructors to run first.
kono
parents:
diff changeset
3054 Linux kernel does not support priorities other than default, and the only
kono
parents:
diff changeset
3055 other user of constructors is coverage. So we run with the default
kono
parents:
diff changeset
3056 priority. */
kono
parents:
diff changeset
3057 int priority = flag_sanitize & SANITIZE_USER_ADDRESS
kono
parents:
diff changeset
3058 ? MAX_RESERVED_INIT_PRIORITY - 1 : DEFAULT_INIT_PRIORITY;
kono
parents:
diff changeset
3059
kono
parents:
diff changeset
3060 if (flag_sanitize & SANITIZE_USER_ADDRESS)
kono
parents:
diff changeset
3061 {
kono
parents:
diff changeset
3062 tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
kono
parents:
diff changeset
3063 append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
kono
parents:
diff changeset
3064 fn = builtin_decl_implicit (BUILT_IN_ASAN_VERSION_MISMATCH_CHECK);
kono
parents:
diff changeset
3065 append_to_statement_list (build_call_expr (fn, 0), &asan_ctor_statements);
kono
parents:
diff changeset
3066 }
kono
parents:
diff changeset
3067 FOR_EACH_DEFINED_VARIABLE (vnode)
kono
parents:
diff changeset
3068 if (TREE_ASM_WRITTEN (vnode->decl)
kono
parents:
diff changeset
3069 && asan_protect_global (vnode->decl))
kono
parents:
diff changeset
3070 ++gcount;
kono
parents:
diff changeset
3071 hash_table<tree_descriptor_hasher> *const_desc_htab = constant_pool_htab ();
kono
parents:
diff changeset
3072 const_desc_htab->traverse<unsigned HOST_WIDE_INT *, count_string_csts>
kono
parents:
diff changeset
3073 (&gcount);
kono
parents:
diff changeset
3074 if (gcount)
kono
parents:
diff changeset
3075 {
kono
parents:
diff changeset
3076 tree type = asan_global_struct (), var, ctor;
kono
parents:
diff changeset
3077 tree dtor_statements = NULL_TREE;
kono
parents:
diff changeset
3078 vec<constructor_elt, va_gc> *v;
kono
parents:
diff changeset
3079 char buf[20];
kono
parents:
diff changeset
3080
kono
parents:
diff changeset
3081 type = build_array_type_nelts (type, gcount);
kono
parents:
diff changeset
3082 ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", 0);
kono
parents:
diff changeset
3083 var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
kono
parents:
diff changeset
3084 type);
kono
parents:
diff changeset
3085 TREE_STATIC (var) = 1;
kono
parents:
diff changeset
3086 TREE_PUBLIC (var) = 0;
kono
parents:
diff changeset
3087 DECL_ARTIFICIAL (var) = 1;
kono
parents:
diff changeset
3088 DECL_IGNORED_P (var) = 1;
kono
parents:
diff changeset
3089 vec_alloc (v, gcount);
kono
parents:
diff changeset
3090 FOR_EACH_DEFINED_VARIABLE (vnode)
kono
parents:
diff changeset
3091 if (TREE_ASM_WRITTEN (vnode->decl)
kono
parents:
diff changeset
3092 && asan_protect_global (vnode->decl))
kono
parents:
diff changeset
3093 asan_add_global (vnode->decl, TREE_TYPE (type), v);
kono
parents:
diff changeset
3094 struct asan_add_string_csts_data aascd;
kono
parents:
diff changeset
3095 aascd.type = TREE_TYPE (type);
kono
parents:
diff changeset
3096 aascd.v = v;
kono
parents:
diff changeset
3097 const_desc_htab->traverse<asan_add_string_csts_data *, add_string_csts>
kono
parents:
diff changeset
3098 (&aascd);
kono
parents:
diff changeset
3099 ctor = build_constructor (type, v);
kono
parents:
diff changeset
3100 TREE_CONSTANT (ctor) = 1;
kono
parents:
diff changeset
3101 TREE_STATIC (ctor) = 1;
kono
parents:
diff changeset
3102 DECL_INITIAL (var) = ctor;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3103 SET_DECL_ALIGN (var, MAX (DECL_ALIGN (var),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3104 ASAN_SHADOW_GRANULARITY * BITS_PER_UNIT));
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3105
111
kono
parents:
diff changeset
3106 varpool_node::finalize_decl (var);
kono
parents:
diff changeset
3107
kono
parents:
diff changeset
3108 tree fn = builtin_decl_implicit (BUILT_IN_ASAN_REGISTER_GLOBALS);
kono
parents:
diff changeset
3109 tree gcount_tree = build_int_cst (pointer_sized_int_node, gcount);
kono
parents:
diff changeset
3110 append_to_statement_list (build_call_expr (fn, 2,
kono
parents:
diff changeset
3111 build_fold_addr_expr (var),
kono
parents:
diff changeset
3112 gcount_tree),
kono
parents:
diff changeset
3113 &asan_ctor_statements);
kono
parents:
diff changeset
3114
kono
parents:
diff changeset
3115 fn = builtin_decl_implicit (BUILT_IN_ASAN_UNREGISTER_GLOBALS);
kono
parents:
diff changeset
3116 append_to_statement_list (build_call_expr (fn, 2,
kono
parents:
diff changeset
3117 build_fold_addr_expr (var),
kono
parents:
diff changeset
3118 gcount_tree),
kono
parents:
diff changeset
3119 &dtor_statements);
kono
parents:
diff changeset
3120 cgraph_build_static_cdtor ('D', dtor_statements, priority);
kono
parents:
diff changeset
3121 }
kono
parents:
diff changeset
3122 if (asan_ctor_statements)
kono
parents:
diff changeset
3123 cgraph_build_static_cdtor ('I', asan_ctor_statements, priority);
kono
parents:
diff changeset
3124 flag_sanitize |= SANITIZE_ADDRESS;
kono
parents:
diff changeset
3125 }
kono
parents:
diff changeset
3126
kono
parents:
diff changeset
3127 /* Poison or unpoison (depending on IS_CLOBBER variable) shadow memory based
kono
parents:
diff changeset
3128 on SHADOW address. Newly added statements will be added to ITER with
kono
parents:
diff changeset
3129 given location LOC. We mark SIZE bytes in shadow memory, where
kono
parents:
diff changeset
3130 LAST_CHUNK_SIZE is greater than zero in situation where we are at the
kono
parents:
diff changeset
3131 end of a variable. */
kono
parents:
diff changeset
3132
kono
parents:
diff changeset
3133 static void
kono
parents:
diff changeset
3134 asan_store_shadow_bytes (gimple_stmt_iterator *iter, location_t loc,
kono
parents:
diff changeset
3135 tree shadow,
kono
parents:
diff changeset
3136 unsigned HOST_WIDE_INT base_addr_offset,
kono
parents:
diff changeset
3137 bool is_clobber, unsigned size,
kono
parents:
diff changeset
3138 unsigned last_chunk_size)
kono
parents:
diff changeset
3139 {
kono
parents:
diff changeset
3140 tree shadow_ptr_type;
kono
parents:
diff changeset
3141
kono
parents:
diff changeset
3142 switch (size)
kono
parents:
diff changeset
3143 {
kono
parents:
diff changeset
3144 case 1:
kono
parents:
diff changeset
3145 shadow_ptr_type = shadow_ptr_types[0];
kono
parents:
diff changeset
3146 break;
kono
parents:
diff changeset
3147 case 2:
kono
parents:
diff changeset
3148 shadow_ptr_type = shadow_ptr_types[1];
kono
parents:
diff changeset
3149 break;
kono
parents:
diff changeset
3150 case 4:
kono
parents:
diff changeset
3151 shadow_ptr_type = shadow_ptr_types[2];
kono
parents:
diff changeset
3152 break;
kono
parents:
diff changeset
3153 default:
kono
parents:
diff changeset
3154 gcc_unreachable ();
kono
parents:
diff changeset
3155 }
kono
parents:
diff changeset
3156
kono
parents:
diff changeset
3157 unsigned char c = (char) is_clobber ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0;
kono
parents:
diff changeset
3158 unsigned HOST_WIDE_INT val = 0;
kono
parents:
diff changeset
3159 unsigned last_pos = size;
kono
parents:
diff changeset
3160 if (last_chunk_size && !is_clobber)
kono
parents:
diff changeset
3161 last_pos = BYTES_BIG_ENDIAN ? 0 : size - 1;
kono
parents:
diff changeset
3162 for (unsigned i = 0; i < size; ++i)
kono
parents:
diff changeset
3163 {
kono
parents:
diff changeset
3164 unsigned char shadow_c = c;
kono
parents:
diff changeset
3165 if (i == last_pos)
kono
parents:
diff changeset
3166 shadow_c = last_chunk_size;
kono
parents:
diff changeset
3167 val |= (unsigned HOST_WIDE_INT) shadow_c << (BITS_PER_UNIT * i);
kono
parents:
diff changeset
3168 }
kono
parents:
diff changeset
3169
kono
parents:
diff changeset
3170 /* Handle last chunk in unpoisoning. */
kono
parents:
diff changeset
3171 tree magic = build_int_cst (TREE_TYPE (shadow_ptr_type), val);
kono
parents:
diff changeset
3172
kono
parents:
diff changeset
3173 tree dest = build2 (MEM_REF, TREE_TYPE (shadow_ptr_type), shadow,
kono
parents:
diff changeset
3174 build_int_cst (shadow_ptr_type, base_addr_offset));
kono
parents:
diff changeset
3175
kono
parents:
diff changeset
3176 gimple *g = gimple_build_assign (dest, magic);
kono
parents:
diff changeset
3177 gimple_set_location (g, loc);
kono
parents:
diff changeset
3178 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3179 }
kono
parents:
diff changeset
3180
kono
parents:
diff changeset
3181 /* Expand the ASAN_MARK builtins. */
kono
parents:
diff changeset
3182
kono
parents:
diff changeset
3183 bool
kono
parents:
diff changeset
3184 asan_expand_mark_ifn (gimple_stmt_iterator *iter)
kono
parents:
diff changeset
3185 {
kono
parents:
diff changeset
3186 gimple *g = gsi_stmt (*iter);
kono
parents:
diff changeset
3187 location_t loc = gimple_location (g);
kono
parents:
diff changeset
3188 HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (g, 0));
kono
parents:
diff changeset
3189 bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
kono
parents:
diff changeset
3190
kono
parents:
diff changeset
3191 tree base = gimple_call_arg (g, 1);
kono
parents:
diff changeset
3192 gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
kono
parents:
diff changeset
3193 tree decl = TREE_OPERAND (base, 0);
kono
parents:
diff changeset
3194
kono
parents:
diff changeset
3195 /* For a nested function, we can have: ASAN_MARK (2, &FRAME.2.fp_input, 4) */
kono
parents:
diff changeset
3196 if (TREE_CODE (decl) == COMPONENT_REF
kono
parents:
diff changeset
3197 && DECL_NONLOCAL_FRAME (TREE_OPERAND (decl, 0)))
kono
parents:
diff changeset
3198 decl = TREE_OPERAND (decl, 0);
kono
parents:
diff changeset
3199
kono
parents:
diff changeset
3200 gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
kono
parents:
diff changeset
3201
kono
parents:
diff changeset
3202 if (is_poison)
kono
parents:
diff changeset
3203 {
kono
parents:
diff changeset
3204 if (asan_handled_variables == NULL)
kono
parents:
diff changeset
3205 asan_handled_variables = new hash_set<tree> (16);
kono
parents:
diff changeset
3206 asan_handled_variables->add (decl);
kono
parents:
diff changeset
3207 }
kono
parents:
diff changeset
3208 tree len = gimple_call_arg (g, 2);
kono
parents:
diff changeset
3209
kono
parents:
diff changeset
3210 gcc_assert (tree_fits_shwi_p (len));
kono
parents:
diff changeset
3211 unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
kono
parents:
diff changeset
3212 gcc_assert (size_in_bytes);
kono
parents:
diff changeset
3213
kono
parents:
diff changeset
3214 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3215 NOP_EXPR, base);
kono
parents:
diff changeset
3216 gimple_set_location (g, loc);
kono
parents:
diff changeset
3217 gsi_replace (iter, g, false);
kono
parents:
diff changeset
3218 tree base_addr = gimple_assign_lhs (g);
kono
parents:
diff changeset
3219
kono
parents:
diff changeset
3220 /* Generate direct emission if size_in_bytes is small. */
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3221 if (size_in_bytes
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3222 <= (unsigned)param_use_after_scope_direct_emission_threshold)
111
kono
parents:
diff changeset
3223 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3224 const unsigned HOST_WIDE_INT shadow_size
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3225 = shadow_mem_size (size_in_bytes);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3226 const unsigned int shadow_align
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3227 = (get_pointer_alignment (base) / BITS_PER_UNIT) >> ASAN_SHADOW_SHIFT;
111
kono
parents:
diff changeset
3228
kono
parents:
diff changeset
3229 tree shadow = build_shadow_mem_access (iter, loc, base_addr,
kono
parents:
diff changeset
3230 shadow_ptr_types[0], true);
kono
parents:
diff changeset
3231
kono
parents:
diff changeset
3232 for (unsigned HOST_WIDE_INT offset = 0; offset < shadow_size;)
kono
parents:
diff changeset
3233 {
kono
parents:
diff changeset
3234 unsigned size = 1;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3235 if (shadow_size - offset >= 4
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3236 && (!STRICT_ALIGNMENT || shadow_align >= 4))
111
kono
parents:
diff changeset
3237 size = 4;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3238 else if (shadow_size - offset >= 2
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
3239 && (!STRICT_ALIGNMENT || shadow_align >= 2))
111
kono
parents:
diff changeset
3240 size = 2;
kono
parents:
diff changeset
3241
kono
parents:
diff changeset
3242 unsigned HOST_WIDE_INT last_chunk_size = 0;
kono
parents:
diff changeset
3243 unsigned HOST_WIDE_INT s = (offset + size) * ASAN_SHADOW_GRANULARITY;
kono
parents:
diff changeset
3244 if (s > size_in_bytes)
kono
parents:
diff changeset
3245 last_chunk_size = ASAN_SHADOW_GRANULARITY - (s - size_in_bytes);
kono
parents:
diff changeset
3246
kono
parents:
diff changeset
3247 asan_store_shadow_bytes (iter, loc, shadow, offset, is_poison,
kono
parents:
diff changeset
3248 size, last_chunk_size);
kono
parents:
diff changeset
3249 offset += size;
kono
parents:
diff changeset
3250 }
kono
parents:
diff changeset
3251 }
kono
parents:
diff changeset
3252 else
kono
parents:
diff changeset
3253 {
kono
parents:
diff changeset
3254 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3255 NOP_EXPR, len);
kono
parents:
diff changeset
3256 gimple_set_location (g, loc);
kono
parents:
diff changeset
3257 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
3258 tree sz_arg = gimple_assign_lhs (g);
kono
parents:
diff changeset
3259
kono
parents:
diff changeset
3260 tree fun
kono
parents:
diff changeset
3261 = builtin_decl_implicit (is_poison ? BUILT_IN_ASAN_POISON_STACK_MEMORY
kono
parents:
diff changeset
3262 : BUILT_IN_ASAN_UNPOISON_STACK_MEMORY);
kono
parents:
diff changeset
3263 g = gimple_build_call (fun, 2, base_addr, sz_arg);
kono
parents:
diff changeset
3264 gimple_set_location (g, loc);
kono
parents:
diff changeset
3265 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3266 }
kono
parents:
diff changeset
3267
kono
parents:
diff changeset
3268 return false;
kono
parents:
diff changeset
3269 }
kono
parents:
diff changeset
3270
kono
parents:
diff changeset
3271 /* Expand the ASAN_{LOAD,STORE} builtins. */
kono
parents:
diff changeset
3272
kono
parents:
diff changeset
3273 bool
kono
parents:
diff changeset
3274 asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
kono
parents:
diff changeset
3275 {
kono
parents:
diff changeset
3276 gimple *g = gsi_stmt (*iter);
kono
parents:
diff changeset
3277 location_t loc = gimple_location (g);
kono
parents:
diff changeset
3278 bool recover_p;
kono
parents:
diff changeset
3279 if (flag_sanitize & SANITIZE_USER_ADDRESS)
kono
parents:
diff changeset
3280 recover_p = (flag_sanitize_recover & SANITIZE_USER_ADDRESS) != 0;
kono
parents:
diff changeset
3281 else
kono
parents:
diff changeset
3282 recover_p = (flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
kono
parents:
diff changeset
3283
kono
parents:
diff changeset
3284 HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
kono
parents:
diff changeset
3285 gcc_assert (flags < ASAN_CHECK_LAST);
kono
parents:
diff changeset
3286 bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
kono
parents:
diff changeset
3287 bool is_store = (flags & ASAN_CHECK_STORE) != 0;
kono
parents:
diff changeset
3288 bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
kono
parents:
diff changeset
3289
kono
parents:
diff changeset
3290 tree base = gimple_call_arg (g, 1);
kono
parents:
diff changeset
3291 tree len = gimple_call_arg (g, 2);
kono
parents:
diff changeset
3292 HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));
kono
parents:
diff changeset
3293
kono
parents:
diff changeset
3294 HOST_WIDE_INT size_in_bytes
kono
parents:
diff changeset
3295 = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
kono
parents:
diff changeset
3296
kono
parents:
diff changeset
3297 if (use_calls)
kono
parents:
diff changeset
3298 {
kono
parents:
diff changeset
3299 /* Instrument using callbacks. */
kono
parents:
diff changeset
3300 gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3301 NOP_EXPR, base);
kono
parents:
diff changeset
3302 gimple_set_location (g, loc);
kono
parents:
diff changeset
3303 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
3304 tree base_addr = gimple_assign_lhs (g);
kono
parents:
diff changeset
3305
kono
parents:
diff changeset
3306 int nargs;
kono
parents:
diff changeset
3307 tree fun = check_func (is_store, recover_p, size_in_bytes, &nargs);
kono
parents:
diff changeset
3308 if (nargs == 1)
kono
parents:
diff changeset
3309 g = gimple_build_call (fun, 1, base_addr);
kono
parents:
diff changeset
3310 else
kono
parents:
diff changeset
3311 {
kono
parents:
diff changeset
3312 gcc_assert (nargs == 2);
kono
parents:
diff changeset
3313 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3314 NOP_EXPR, len);
kono
parents:
diff changeset
3315 gimple_set_location (g, loc);
kono
parents:
diff changeset
3316 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
3317 tree sz_arg = gimple_assign_lhs (g);
kono
parents:
diff changeset
3318 g = gimple_build_call (fun, nargs, base_addr, sz_arg);
kono
parents:
diff changeset
3319 }
kono
parents:
diff changeset
3320 gimple_set_location (g, loc);
kono
parents:
diff changeset
3321 gsi_replace (iter, g, false);
kono
parents:
diff changeset
3322 return false;
kono
parents:
diff changeset
3323 }
kono
parents:
diff changeset
3324
kono
parents:
diff changeset
3325 HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
kono
parents:
diff changeset
3326
kono
parents:
diff changeset
3327 tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
kono
parents:
diff changeset
3328 tree shadow_type = TREE_TYPE (shadow_ptr_type);
kono
parents:
diff changeset
3329
kono
parents:
diff changeset
3330 gimple_stmt_iterator gsi = *iter;
kono
parents:
diff changeset
3331
kono
parents:
diff changeset
3332 if (!is_non_zero_len)
kono
parents:
diff changeset
3333 {
kono
parents:
diff changeset
3334 /* So, the length of the memory area to asan-protect is
kono
parents:
diff changeset
3335 non-constant. Let's guard the generated instrumentation code
kono
parents:
diff changeset
3336 like:
kono
parents:
diff changeset
3337
kono
parents:
diff changeset
3338 if (len != 0)
kono
parents:
diff changeset
3339 {
kono
parents:
diff changeset
3340 //asan instrumentation code goes here.
kono
parents:
diff changeset
3341 }
kono
parents:
diff changeset
3342 // falltrough instructions, starting with *ITER. */
kono
parents:
diff changeset
3343
kono
parents:
diff changeset
3344 g = gimple_build_cond (NE_EXPR,
kono
parents:
diff changeset
3345 len,
kono
parents:
diff changeset
3346 build_int_cst (TREE_TYPE (len), 0),
kono
parents:
diff changeset
3347 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
3348 gimple_set_location (g, loc);
kono
parents:
diff changeset
3349
kono
parents:
diff changeset
3350 basic_block then_bb, fallthrough_bb;
kono
parents:
diff changeset
3351 insert_if_then_before_iter (as_a <gcond *> (g), iter,
kono
parents:
diff changeset
3352 /*then_more_likely_p=*/true,
kono
parents:
diff changeset
3353 &then_bb, &fallthrough_bb);
kono
parents:
diff changeset
3354 /* Note that fallthrough_bb starts with the statement that was
kono
parents:
diff changeset
3355 pointed to by ITER. */
kono
parents:
diff changeset
3356
kono
parents:
diff changeset
3357 /* The 'then block' of the 'if (len != 0) condition is where
kono
parents:
diff changeset
3358 we'll generate the asan instrumentation code now. */
kono
parents:
diff changeset
3359 gsi = gsi_last_bb (then_bb);
kono
parents:
diff changeset
3360 }
kono
parents:
diff changeset
3361
kono
parents:
diff changeset
3362 /* Get an iterator on the point where we can add the condition
kono
parents:
diff changeset
3363 statement for the instrumentation. */
kono
parents:
diff changeset
3364 basic_block then_bb, else_bb;
kono
parents:
diff changeset
3365 gsi = create_cond_insert_point (&gsi, /*before_p*/false,
kono
parents:
diff changeset
3366 /*then_more_likely_p=*/false,
kono
parents:
diff changeset
3367 /*create_then_fallthru_edge*/recover_p,
kono
parents:
diff changeset
3368 &then_bb,
kono
parents:
diff changeset
3369 &else_bb);
kono
parents:
diff changeset
3370
kono
parents:
diff changeset
3371 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3372 NOP_EXPR, base);
kono
parents:
diff changeset
3373 gimple_set_location (g, loc);
kono
parents:
diff changeset
3374 gsi_insert_before (&gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3375 tree base_addr = gimple_assign_lhs (g);
kono
parents:
diff changeset
3376
kono
parents:
diff changeset
3377 tree t = NULL_TREE;
kono
parents:
diff changeset
3378 if (real_size_in_bytes >= 8)
kono
parents:
diff changeset
3379 {
kono
parents:
diff changeset
3380 tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
kono
parents:
diff changeset
3381 shadow_ptr_type);
kono
parents:
diff changeset
3382 t = shadow;
kono
parents:
diff changeset
3383 }
kono
parents:
diff changeset
3384 else
kono
parents:
diff changeset
3385 {
kono
parents:
diff changeset
3386 /* Slow path for 1, 2 and 4 byte accesses. */
kono
parents:
diff changeset
3387 /* Test (shadow != 0)
kono
parents:
diff changeset
3388 & ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */
kono
parents:
diff changeset
3389 tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
kono
parents:
diff changeset
3390 shadow_ptr_type);
kono
parents:
diff changeset
3391 gimple *shadow_test = build_assign (NE_EXPR, shadow, 0);
kono
parents:
diff changeset
3392 gimple_seq seq = NULL;
kono
parents:
diff changeset
3393 gimple_seq_add_stmt (&seq, shadow_test);
kono
parents:
diff changeset
3394 /* Aligned (>= 8 bytes) can test just
kono
parents:
diff changeset
3395 (real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
kono
parents:
diff changeset
3396 to be 0. */
kono
parents:
diff changeset
3397 if (align < 8)
kono
parents:
diff changeset
3398 {
kono
parents:
diff changeset
3399 gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
kono
parents:
diff changeset
3400 base_addr, 7));
kono
parents:
diff changeset
3401 gimple_seq_add_stmt (&seq,
kono
parents:
diff changeset
3402 build_type_cast (shadow_type,
kono
parents:
diff changeset
3403 gimple_seq_last (seq)));
kono
parents:
diff changeset
3404 if (real_size_in_bytes > 1)
kono
parents:
diff changeset
3405 gimple_seq_add_stmt (&seq,
kono
parents:
diff changeset
3406 build_assign (PLUS_EXPR,
kono
parents:
diff changeset
3407 gimple_seq_last (seq),
kono
parents:
diff changeset
3408 real_size_in_bytes - 1));
kono
parents:
diff changeset
3409 t = gimple_assign_lhs (gimple_seq_last_stmt (seq));
kono
parents:
diff changeset
3410 }
kono
parents:
diff changeset
3411 else
kono
parents:
diff changeset
3412 t = build_int_cst (shadow_type, real_size_in_bytes - 1);
kono
parents:
diff changeset
3413 gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, t, shadow));
kono
parents:
diff changeset
3414 gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
kono
parents:
diff changeset
3415 gimple_seq_last (seq)));
kono
parents:
diff changeset
3416 t = gimple_assign_lhs (gimple_seq_last (seq));
kono
parents:
diff changeset
3417 gimple_seq_set_location (seq, loc);
kono
parents:
diff changeset
3418 gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
kono
parents:
diff changeset
3419
kono
parents:
diff changeset
3420 /* For non-constant, misaligned or otherwise weird access sizes,
kono
parents:
diff changeset
3421 check first and last byte. */
kono
parents:
diff changeset
3422 if (size_in_bytes == -1)
kono
parents:
diff changeset
3423 {
kono
parents:
diff changeset
3424 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3425 MINUS_EXPR, len,
kono
parents:
diff changeset
3426 build_int_cst (pointer_sized_int_node, 1));
kono
parents:
diff changeset
3427 gimple_set_location (g, loc);
kono
parents:
diff changeset
3428 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3429 tree last = gimple_assign_lhs (g);
kono
parents:
diff changeset
3430 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
3431 PLUS_EXPR, base_addr, last);
kono
parents:
diff changeset
3432 gimple_set_location (g, loc);
kono
parents:
diff changeset
3433 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3434 tree base_end_addr = gimple_assign_lhs (g);
kono
parents:
diff changeset
3435
kono
parents:
diff changeset
3436 tree shadow = build_shadow_mem_access (&gsi, loc, base_end_addr,
kono
parents:
diff changeset
3437 shadow_ptr_type);
kono
parents:
diff changeset
3438 gimple *shadow_test = build_assign (NE_EXPR, shadow, 0);
kono
parents:
diff changeset
3439 gimple_seq seq = NULL;
kono
parents:
diff changeset
3440 gimple_seq_add_stmt (&seq, shadow_test);
kono
parents:
diff changeset
3441 gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
kono
parents:
diff changeset
3442 base_end_addr, 7));
kono
parents:
diff changeset
3443 gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
kono
parents:
diff changeset
3444 gimple_seq_last (seq)));
kono
parents:
diff changeset
3445 gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
kono
parents:
diff changeset
3446 gimple_seq_last (seq),
kono
parents:
diff changeset
3447 shadow));
kono
parents:
diff changeset
3448 gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
kono
parents:
diff changeset
3449 gimple_seq_last (seq)));
kono
parents:
diff changeset
3450 gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
kono
parents:
diff changeset
3451 gimple_seq_last (seq)));
kono
parents:
diff changeset
3452 t = gimple_assign_lhs (gimple_seq_last (seq));
kono
parents:
diff changeset
3453 gimple_seq_set_location (seq, loc);
kono
parents:
diff changeset
3454 gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
kono
parents:
diff changeset
3455 }
kono
parents:
diff changeset
3456 }
kono
parents:
diff changeset
3457
kono
parents:
diff changeset
3458 g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
kono
parents:
diff changeset
3459 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
3460 gimple_set_location (g, loc);
kono
parents:
diff changeset
3461 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3462
kono
parents:
diff changeset
3463 /* Generate call to the run-time library (e.g. __asan_report_load8). */
kono
parents:
diff changeset
3464 gsi = gsi_start_bb (then_bb);
kono
parents:
diff changeset
3465 int nargs;
kono
parents:
diff changeset
3466 tree fun = report_error_func (is_store, recover_p, size_in_bytes, &nargs);
kono
parents:
diff changeset
3467 g = gimple_build_call (fun, nargs, base_addr, len);
kono
parents:
diff changeset
3468 gimple_set_location (g, loc);
kono
parents:
diff changeset
3469 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
3470
kono
parents:
diff changeset
3471 gsi_remove (iter, true);
kono
parents:
diff changeset
3472 *iter = gsi_start_bb (else_bb);
kono
parents:
diff changeset
3473
kono
parents:
diff changeset
3474 return true;
kono
parents:
diff changeset
3475 }
kono
parents:
diff changeset
3476
kono
parents:
diff changeset
3477 /* Create ASAN shadow variable for a VAR_DECL which has been rewritten
kono
parents:
diff changeset
3478 into SSA. Already seen VAR_DECLs are stored in SHADOW_VARS_MAPPING. */
kono
parents:
diff changeset
3479
kono
parents:
diff changeset
3480 static tree
kono
parents:
diff changeset
3481 create_asan_shadow_var (tree var_decl,
kono
parents:
diff changeset
3482 hash_map<tree, tree> &shadow_vars_mapping)
kono
parents:
diff changeset
3483 {
kono
parents:
diff changeset
3484 tree *slot = shadow_vars_mapping.get (var_decl);
kono
parents:
diff changeset
3485 if (slot == NULL)
kono
parents:
diff changeset
3486 {
kono
parents:
diff changeset
3487 tree shadow_var = copy_node (var_decl);
kono
parents:
diff changeset
3488
kono
parents:
diff changeset
3489 copy_body_data id;
kono
parents:
diff changeset
3490 memset (&id, 0, sizeof (copy_body_data));
kono
parents:
diff changeset
3491 id.src_fn = id.dst_fn = current_function_decl;
kono
parents:
diff changeset
3492 copy_decl_for_dup_finish (&id, var_decl, shadow_var);
kono
parents:
diff changeset
3493
kono
parents:
diff changeset
3494 DECL_ARTIFICIAL (shadow_var) = 1;
kono
parents:
diff changeset
3495 DECL_IGNORED_P (shadow_var) = 1;
kono
parents:
diff changeset
3496 DECL_SEEN_IN_BIND_EXPR_P (shadow_var) = 0;
kono
parents:
diff changeset
3497 gimple_add_tmp_var (shadow_var);
kono
parents:
diff changeset
3498
kono
parents:
diff changeset
3499 shadow_vars_mapping.put (var_decl, shadow_var);
kono
parents:
diff changeset
3500 return shadow_var;
kono
parents:
diff changeset
3501 }
kono
parents:
diff changeset
3502 else
kono
parents:
diff changeset
3503 return *slot;
kono
parents:
diff changeset
3504 }
kono
parents:
diff changeset
3505
kono
parents:
diff changeset
3506 /* Expand ASAN_POISON ifn. */
kono
parents:
diff changeset
3507
kono
parents:
diff changeset
3508 bool
kono
parents:
diff changeset
3509 asan_expand_poison_ifn (gimple_stmt_iterator *iter,
kono
parents:
diff changeset
3510 bool *need_commit_edge_insert,
kono
parents:
diff changeset
3511 hash_map<tree, tree> &shadow_vars_mapping)
kono
parents:
diff changeset
3512 {
kono
parents:
diff changeset
3513 gimple *g = gsi_stmt (*iter);
kono
parents:
diff changeset
3514 tree poisoned_var = gimple_call_lhs (g);
kono
parents:
diff changeset
3515 if (!poisoned_var || has_zero_uses (poisoned_var))
kono
parents:
diff changeset
3516 {
kono
parents:
diff changeset
3517 gsi_remove (iter, true);
kono
parents:
diff changeset
3518 return true;
kono
parents:
diff changeset
3519 }
kono
parents:
diff changeset
3520
kono
parents:
diff changeset
3521 if (SSA_NAME_VAR (poisoned_var) == NULL_TREE)
kono
parents:
diff changeset
3522 SET_SSA_NAME_VAR_OR_IDENTIFIER (poisoned_var,
kono
parents:
diff changeset
3523 create_tmp_var (TREE_TYPE (poisoned_var)));
kono
parents:
diff changeset
3524
kono
parents:
diff changeset
3525 tree shadow_var = create_asan_shadow_var (SSA_NAME_VAR (poisoned_var),
kono
parents:
diff changeset
3526 shadow_vars_mapping);
kono
parents:
diff changeset
3527
kono
parents:
diff changeset
3528 bool recover_p;
kono
parents:
diff changeset
3529 if (flag_sanitize & SANITIZE_USER_ADDRESS)
kono
parents:
diff changeset
3530 recover_p = (flag_sanitize_recover & SANITIZE_USER_ADDRESS) != 0;
kono
parents:
diff changeset
3531 else
kono
parents:
diff changeset
3532 recover_p = (flag_sanitize_recover & SANITIZE_KERNEL_ADDRESS) != 0;
kono
parents:
diff changeset
3533 tree size = DECL_SIZE_UNIT (shadow_var);
kono
parents:
diff changeset
3534 gimple *poison_call
kono
parents:
diff changeset
3535 = gimple_build_call_internal (IFN_ASAN_MARK, 3,
kono
parents:
diff changeset
3536 build_int_cst (integer_type_node,
kono
parents:
diff changeset
3537 ASAN_MARK_POISON),
kono
parents:
diff changeset
3538 build_fold_addr_expr (shadow_var), size);
kono
parents:
diff changeset
3539
kono
parents:
diff changeset
3540 gimple *use;
kono
parents:
diff changeset
3541 imm_use_iterator imm_iter;
kono
parents:
diff changeset
3542 FOR_EACH_IMM_USE_STMT (use, imm_iter, poisoned_var)
kono
parents:
diff changeset
3543 {
kono
parents:
diff changeset
3544 if (is_gimple_debug (use))
kono
parents:
diff changeset
3545 continue;
kono
parents:
diff changeset
3546
kono
parents:
diff changeset
3547 int nargs;
kono
parents:
diff changeset
3548 bool store_p = gimple_call_internal_p (use, IFN_ASAN_POISON_USE);
kono
parents:
diff changeset
3549 tree fun = report_error_func (store_p, recover_p, tree_to_uhwi (size),
kono
parents:
diff changeset
3550 &nargs);
kono
parents:
diff changeset
3551
kono
parents:
diff changeset
3552 gcall *call = gimple_build_call (fun, 1,
kono
parents:
diff changeset
3553 build_fold_addr_expr (shadow_var));
kono
parents:
diff changeset
3554 gimple_set_location (call, gimple_location (use));
kono
parents:
diff changeset
3555 gimple *call_to_insert = call;
kono
parents:
diff changeset
3556
kono
parents:
diff changeset
3557 /* The USE can be a gimple PHI node. If so, insert the call on
kono
parents:
diff changeset
3558 all edges leading to the PHI node. */
kono
parents:
diff changeset
3559 if (is_a <gphi *> (use))
kono
parents:
diff changeset
3560 {
kono
parents:
diff changeset
3561 gphi *phi = dyn_cast<gphi *> (use);
kono
parents:
diff changeset
3562 for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
kono
parents:
diff changeset
3563 if (gimple_phi_arg_def (phi, i) == poisoned_var)
kono
parents:
diff changeset
3564 {
kono
parents:
diff changeset
3565 edge e = gimple_phi_arg_edge (phi, i);
kono
parents:
diff changeset
3566
kono
parents:
diff changeset
3567 /* Do not insert on an edge we can't split. */
kono
parents:
diff changeset
3568 if (e->flags & EDGE_ABNORMAL)
kono
parents:
diff changeset
3569 continue;
kono
parents:
diff changeset
3570
kono
parents:
diff changeset
3571 if (call_to_insert == NULL)
kono
parents:
diff changeset
3572 call_to_insert = gimple_copy (call);
kono
parents:
diff changeset
3573
kono
parents:
diff changeset
3574 gsi_insert_seq_on_edge (e, call_to_insert);
kono
parents:
diff changeset
3575 *need_commit_edge_insert = true;
kono
parents:
diff changeset
3576 call_to_insert = NULL;
kono
parents:
diff changeset
3577 }
kono
parents:
diff changeset
3578 }
kono
parents:
diff changeset
3579 else
kono
parents:
diff changeset
3580 {
kono
parents:
diff changeset
3581 gimple_stmt_iterator gsi = gsi_for_stmt (use);
kono
parents:
diff changeset
3582 if (store_p)
kono
parents:
diff changeset
3583 gsi_replace (&gsi, call, true);
kono
parents:
diff changeset
3584 else
kono
parents:
diff changeset
3585 gsi_insert_before (&gsi, call, GSI_NEW_STMT);
kono
parents:
diff changeset
3586 }
kono
parents:
diff changeset
3587 }
kono
parents:
diff changeset
3588
kono
parents:
diff changeset
3589 SSA_NAME_IS_DEFAULT_DEF (poisoned_var) = true;
kono
parents:
diff changeset
3590 SSA_NAME_DEF_STMT (poisoned_var) = gimple_build_nop ();
kono
parents:
diff changeset
3591 gsi_replace (iter, poison_call, false);
kono
parents:
diff changeset
3592
kono
parents:
diff changeset
3593 return true;
kono
parents:
diff changeset
3594 }
kono
parents:
diff changeset
3595
kono
parents:
diff changeset
3596 /* Instrument the current function. */
kono
parents:
diff changeset
3597
kono
parents:
diff changeset
3598 static unsigned int
kono
parents:
diff changeset
3599 asan_instrument (void)
kono
parents:
diff changeset
3600 {
kono
parents:
diff changeset
3601 if (shadow_ptr_types[0] == NULL_TREE)
kono
parents:
diff changeset
3602 asan_init_shadow_ptr_types ();
kono
parents:
diff changeset
3603 transform_statements ();
kono
parents:
diff changeset
3604 last_alloca_addr = NULL_TREE;
kono
parents:
diff changeset
3605 return 0;
kono
parents:
diff changeset
3606 }
kono
parents:
diff changeset
3607
kono
parents:
diff changeset
3608 static bool
kono
parents:
diff changeset
3609 gate_asan (void)
kono
parents:
diff changeset
3610 {
kono
parents:
diff changeset
3611 return sanitize_flags_p (SANITIZE_ADDRESS);
kono
parents:
diff changeset
3612 }
kono
parents:
diff changeset
3613
kono
parents:
diff changeset
3614 namespace {
kono
parents:
diff changeset
3615
kono
parents:
diff changeset
3616 const pass_data pass_data_asan =
kono
parents:
diff changeset
3617 {
kono
parents:
diff changeset
3618 GIMPLE_PASS, /* type */
kono
parents:
diff changeset
3619 "asan", /* name */
kono
parents:
diff changeset
3620 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
3621 TV_NONE, /* tv_id */
kono
parents:
diff changeset
3622 ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
kono
parents:
diff changeset
3623 0, /* properties_provided */
kono
parents:
diff changeset
3624 0, /* properties_destroyed */
kono
parents:
diff changeset
3625 0, /* todo_flags_start */
kono
parents:
diff changeset
3626 TODO_update_ssa, /* todo_flags_finish */
kono
parents:
diff changeset
3627 };
kono
parents:
diff changeset
3628
kono
parents:
diff changeset
3629 class pass_asan : public gimple_opt_pass
kono
parents:
diff changeset
3630 {
kono
parents:
diff changeset
3631 public:
kono
parents:
diff changeset
3632 pass_asan (gcc::context *ctxt)
kono
parents:
diff changeset
3633 : gimple_opt_pass (pass_data_asan, ctxt)
kono
parents:
diff changeset
3634 {}
kono
parents:
diff changeset
3635
kono
parents:
diff changeset
3636 /* opt_pass methods: */
kono
parents:
diff changeset
3637 opt_pass * clone () { return new pass_asan (m_ctxt); }
kono
parents:
diff changeset
3638 virtual bool gate (function *) { return gate_asan (); }
kono
parents:
diff changeset
3639 virtual unsigned int execute (function *) { return asan_instrument (); }
kono
parents:
diff changeset
3640
kono
parents:
diff changeset
3641 }; // class pass_asan
kono
parents:
diff changeset
3642
kono
parents:
diff changeset
3643 } // anon namespace
kono
parents:
diff changeset
3644
kono
parents:
diff changeset
3645 gimple_opt_pass *
kono
parents:
diff changeset
3646 make_pass_asan (gcc::context *ctxt)
kono
parents:
diff changeset
3647 {
kono
parents:
diff changeset
3648 return new pass_asan (ctxt);
kono
parents:
diff changeset
3649 }
kono
parents:
diff changeset
3650
kono
parents:
diff changeset
3651 namespace {
kono
parents:
diff changeset
3652
kono
parents:
diff changeset
3653 const pass_data pass_data_asan_O0 =
kono
parents:
diff changeset
3654 {
kono
parents:
diff changeset
3655 GIMPLE_PASS, /* type */
kono
parents:
diff changeset
3656 "asan0", /* name */
kono
parents:
diff changeset
3657 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
3658 TV_NONE, /* tv_id */
kono
parents:
diff changeset
3659 ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
kono
parents:
diff changeset
3660 0, /* properties_provided */
kono
parents:
diff changeset
3661 0, /* properties_destroyed */
kono
parents:
diff changeset
3662 0, /* todo_flags_start */
kono
parents:
diff changeset
3663 TODO_update_ssa, /* todo_flags_finish */
kono
parents:
diff changeset
3664 };
kono
parents:
diff changeset
3665
kono
parents:
diff changeset
3666 class pass_asan_O0 : public gimple_opt_pass
kono
parents:
diff changeset
3667 {
kono
parents:
diff changeset
3668 public:
kono
parents:
diff changeset
3669 pass_asan_O0 (gcc::context *ctxt)
kono
parents:
diff changeset
3670 : gimple_opt_pass (pass_data_asan_O0, ctxt)
kono
parents:
diff changeset
3671 {}
kono
parents:
diff changeset
3672
kono
parents:
diff changeset
3673 /* opt_pass methods: */
kono
parents:
diff changeset
3674 virtual bool gate (function *) { return !optimize && gate_asan (); }
kono
parents:
diff changeset
3675 virtual unsigned int execute (function *) { return asan_instrument (); }
kono
parents:
diff changeset
3676
kono
parents:
diff changeset
3677 }; // class pass_asan_O0
kono
parents:
diff changeset
3678
kono
parents:
diff changeset
3679 } // anon namespace
kono
parents:
diff changeset
3680
kono
parents:
diff changeset
3681 gimple_opt_pass *
kono
parents:
diff changeset
3682 make_pass_asan_O0 (gcc::context *ctxt)
kono
parents:
diff changeset
3683 {
kono
parents:
diff changeset
3684 return new pass_asan_O0 (ctxt);
kono
parents:
diff changeset
3685 }
kono
parents:
diff changeset
3686
kono
parents:
diff changeset
3687 #include "gt-asan.h"