annotate gcc/asan.c @ 16:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
16
kono
parents:
diff changeset
1 /* AddressSanitizer, a fast memory error detector.
kono
parents:
diff changeset
2 Copyright (C) 2012-2017 Free Software Foundation, Inc.
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 "params.h"
kono
parents:
diff changeset
63 #include "builtins.h"
kono
parents:
diff changeset
64 #include "fnmatch.h"
kono
parents:
diff changeset
65 #include "tree-inline.h"
kono
parents:
diff changeset
66
kono
parents:
diff changeset
67 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
kono
parents:
diff changeset
68 with <2x slowdown on average.
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 The tool consists of two parts:
kono
parents:
diff changeset
71 instrumentation module (this file) and a run-time library.
kono
parents:
diff changeset
72 The instrumentation module adds a run-time check before every memory insn.
kono
parents:
diff changeset
73 For a 8- or 16- byte load accessing address X:
kono
parents:
diff changeset
74 ShadowAddr = (X >> 3) + Offset
kono
parents:
diff changeset
75 ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access.
kono
parents:
diff changeset
76 if (ShadowValue)
kono
parents:
diff changeset
77 __asan_report_load8(X);
kono
parents:
diff changeset
78 For a load of N bytes (N=1, 2 or 4) from address X:
kono
parents:
diff changeset
79 ShadowAddr = (X >> 3) + Offset
kono
parents:
diff changeset
80 ShadowValue = *(char*)ShadowAddr;
kono
parents:
diff changeset
81 if (ShadowValue)
kono
parents:
diff changeset
82 if ((X & 7) + N - 1 > ShadowValue)
kono
parents:
diff changeset
83 __asan_report_loadN(X);
kono
parents:
diff changeset
84 Stores are instrumented similarly, but using __asan_report_storeN functions.
kono
parents:
diff changeset
85 A call too __asan_init_vN() is inserted to the list of module CTORs.
kono
parents:
diff changeset
86 N is the version number of the AddressSanitizer API. The changes between the
kono
parents:
diff changeset
87 API versions are listed in libsanitizer/asan/asan_interface_internal.h.
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 The run-time library redefines malloc (so that redzone are inserted around
kono
parents:
diff changeset
90 the allocated memory) and free (so that reuse of free-ed memory is delayed),
kono
parents:
diff changeset
91 provides __asan_report* and __asan_init_vN functions.
kono
parents:
diff changeset
92
kono
parents:
diff changeset
93 Read more:
kono
parents:
diff changeset
94 http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 The current implementation supports detection of out-of-bounds and
kono
parents:
diff changeset
97 use-after-free in the heap, on the stack and for global variables.
kono
parents:
diff changeset
98
kono
parents:
diff changeset
99 [Protection of stack variables]
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 To understand how detection of out-of-bounds and use-after-free works
kono
parents:
diff changeset
102 for stack variables, lets look at this example on x86_64 where the
kono
parents:
diff changeset
103 stack grows downward:
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 int
kono
parents:
diff changeset
106 foo ()
kono
parents:
diff changeset
107 {
kono
parents:
diff changeset
108 char a[23] = {0};
kono
parents:
diff changeset
109 int b[2] = {0};
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 a[5] = 1;
kono
parents:
diff changeset
112 b[1] = 2;
kono
parents:
diff changeset
113
kono
parents:
diff changeset
114 return a[5] + b[1];
kono
parents:
diff changeset
115 }
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 For this function, the stack protected by asan will be organized as
kono
parents:
diff changeset
118 follows, from the top of the stack to the bottom:
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make
kono
parents:
diff changeset
123 the next slot be 32 bytes aligned; this one is called Partial
kono
parents:
diff changeset
124 Redzone; this 32 bytes alignment is an asan constraint]
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 Slot 3/ [24 bytes for variable 'a']
kono
parents:
diff changeset
127
kono
parents:
diff changeset
128 Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
kono
parents:
diff changeset
129
kono
parents:
diff changeset
130 Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2]
kono
parents:
diff changeset
131
kono
parents:
diff changeset
132 Slot 6/ [8 bytes for variable 'b']
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called
kono
parents:
diff changeset
135 'LEFT RedZone']
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 The 32 bytes of LEFT red zone at the bottom of the stack can be
kono
parents:
diff changeset
138 decomposed as such:
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 1/ The first 8 bytes contain a magical asan number that is always
kono
parents:
diff changeset
141 0x41B58AB3.
kono
parents:
diff changeset
142
kono
parents:
diff changeset
143 2/ The following 8 bytes contains a pointer to a string (to be
kono
parents:
diff changeset
144 parsed at runtime by the runtime asan library), which format is
kono
parents:
diff changeset
145 the following:
kono
parents:
diff changeset
146
kono
parents:
diff changeset
147 "<function-name> <space> <num-of-variables-on-the-stack>
kono
parents:
diff changeset
148 (<32-bytes-aligned-offset-in-bytes-of-variable> <space>
kono
parents:
diff changeset
149 <length-of-var-in-bytes> ){n} "
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 where '(...){n}' means the content inside the parenthesis occurs 'n'
kono
parents:
diff changeset
152 times, with 'n' being the number of variables on the stack.
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 3/ The following 8 bytes contain the PC of the current function which
kono
parents:
diff changeset
155 will be used by the run-time library to print an error message.
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 4/ The following 8 bytes are reserved for internal use by the run-time.
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159 The shadow memory for that stack layout is going to look like this:
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 - content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1.
kono
parents:
diff changeset
162 The F1 byte pattern is a magic number called
kono
parents:
diff changeset
163 ASAN_STACK_MAGIC_LEFT and is a way for the runtime to know that
kono
parents:
diff changeset
164 the memory for that shadow byte is part of a the LEFT red zone
kono
parents:
diff changeset
165 intended to seat at the bottom of the variables on the stack.
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 - content of shadow memory 8 bytes for slots 6 and 5:
kono
parents:
diff changeset
168 0xF4F4F400. The F4 byte pattern is a magic number
kono
parents:
diff changeset
169 called ASAN_STACK_MAGIC_PARTIAL. It flags the fact that the
kono
parents:
diff changeset
170 memory region for this shadow byte is a PARTIAL red zone
kono
parents:
diff changeset
171 intended to pad a variable A, so that the slot following
kono
parents:
diff changeset
172 {A,padding} is 32 bytes aligned.
kono
parents:
diff changeset
173
kono
parents:
diff changeset
174 Note that the fact that the least significant byte of this
kono
parents:
diff changeset
175 shadow memory content is 00 means that 8 bytes of its
kono
parents:
diff changeset
176 corresponding memory (which corresponds to the memory of
kono
parents:
diff changeset
177 variable 'b') is addressable.
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 - content of shadow memory 8 bytes for slot 4: 0xF2F2F2F2.
kono
parents:
diff changeset
180 The F2 byte pattern is a magic number called
kono
parents:
diff changeset
181 ASAN_STACK_MAGIC_MIDDLE. It flags the fact that the memory
kono
parents:
diff changeset
182 region for this shadow byte is a MIDDLE red zone intended to
kono
parents:
diff changeset
183 seat between two 32 aligned slots of {variable,padding}.
kono
parents:
diff changeset
184
kono
parents:
diff changeset
185 - content of shadow memory 8 bytes for slot 3 and 2:
kono
parents:
diff changeset
186 0xF4000000. This represents is the concatenation of
kono
parents:
diff changeset
187 variable 'a' and the partial red zone following it, like what we
kono
parents:
diff changeset
188 had for variable 'b'. The least significant 3 bytes being 00
kono
parents:
diff changeset
189 means that the 3 bytes of variable 'a' are addressable.
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 - content of shadow memory 8 bytes for slot 1: 0xF3F3F3F3.
kono
parents:
diff changeset
192 The F3 byte pattern is a magic number called
kono
parents:
diff changeset
193 ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory
kono
parents:
diff changeset
194 region for this shadow byte is a RIGHT red zone intended to seat
kono
parents:
diff changeset
195 at the top of the variables of the stack.
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 Note that the real variable layout is done in expand_used_vars in
kono
parents:
diff changeset
198 cfgexpand.c. As far as Address Sanitizer is concerned, it lays out
kono
parents:
diff changeset
199 stack variables as well as the different red zones, emits some
kono
parents:
diff changeset
200 prologue code to populate the shadow memory as to poison (mark as
kono
parents:
diff changeset
201 non-accessible) the regions of the red zones and mark the regions of
kono
parents:
diff changeset
202 stack variables as accessible, and emit some epilogue code to
kono
parents:
diff changeset
203 un-poison (mark as accessible) the regions of red zones right before
kono
parents:
diff changeset
204 the function exits.
kono
parents:
diff changeset
205
kono
parents:
diff changeset
206 [Protection of global variables]
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 The basic idea is to insert a red zone between two global variables
kono
parents:
diff changeset
209 and install a constructor function that calls the asan runtime to do
kono
parents:
diff changeset
210 the populating of the relevant shadow memory regions at load time.
kono
parents:
diff changeset
211
kono
parents:
diff changeset
212 So the global variables are laid out as to insert a red zone between
kono
parents:
diff changeset
213 them. The size of the red zones is so that each variable starts on a
kono
parents:
diff changeset
214 32 bytes boundary.
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 Then a constructor function is installed so that, for each global
kono
parents:
diff changeset
217 variable, it calls the runtime asan library function
kono
parents:
diff changeset
218 __asan_register_globals_with an instance of this type:
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 struct __asan_global
kono
parents:
diff changeset
221 {
kono
parents:
diff changeset
222 // Address of the beginning of the global variable.
kono
parents:
diff changeset
223 const void *__beg;
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 // Initial size of the global variable.
kono
parents:
diff changeset
226 uptr __size;
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 // Size of the global variable + size of the red zone. This
kono
parents:
diff changeset
229 // size is 32 bytes aligned.
kono
parents:
diff changeset
230 uptr __size_with_redzone;
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 // Name of the global variable.
kono
parents:
diff changeset
233 const void *__name;
kono
parents:
diff changeset
234
kono
parents:
diff changeset
235 // Name of the module where the global variable is declared.
kono
parents:
diff changeset
236 const void *__module_name;
kono
parents:
diff changeset
237
kono
parents:
diff changeset
238 // 1 if it has dynamic initialization, 0 otherwise.
kono
parents:
diff changeset
239 uptr __has_dynamic_init;
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 // A pointer to struct that contains source location, could be NULL.
kono
parents:
diff changeset
242 __asan_global_source_location *__location;
kono
parents:
diff changeset
243 }
kono
parents:
diff changeset
244
kono
parents:
diff changeset
245 A destructor function that calls the runtime asan library function
kono
parents:
diff changeset
246 _asan_unregister_globals is also installed. */
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 static unsigned HOST_WIDE_INT asan_shadow_offset_value;
kono
parents:
diff changeset
249 static bool asan_shadow_offset_computed;
kono
parents:
diff changeset
250 static vec<char *> sanitized_sections;
kono
parents:
diff changeset
251 static tree last_alloca_addr;
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 /* Set of variable declarations that are going to be guarded by
kono
parents:
diff changeset
254 use-after-scope sanitizer. */
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 static hash_set<tree> *asan_handled_variables = NULL;
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 hash_set <tree> *asan_used_labels = NULL;
kono
parents:
diff changeset
259
kono
parents:
diff changeset
260 /* Sets shadow offset to value in string VAL. */
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 bool
kono
parents:
diff changeset
263 set_asan_shadow_offset (const char *val)
kono
parents:
diff changeset
264 {
kono
parents:
diff changeset
265 char *endp;
kono
parents:
diff changeset
266
kono
parents:
diff changeset
267 errno = 0;
kono
parents:
diff changeset
268 #ifdef HAVE_LONG_LONG
kono
parents:
diff changeset
269 asan_shadow_offset_value = strtoull (val, &endp, 0);
kono
parents:
diff changeset
270 #else
kono
parents:
diff changeset
271 asan_shadow_offset_value = strtoul (val, &endp, 0);
kono
parents:
diff changeset
272 #endif
kono
parents:
diff changeset
273 if (!(*val != '\0' && *endp == '\0' && errno == 0))
kono
parents:
diff changeset
274 return false;
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 asan_shadow_offset_computed = true;
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 return true;
kono
parents:
diff changeset
279 }
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 /* Set list of user-defined sections that need to be sanitized. */
kono
parents:
diff changeset
282
kono
parents:
diff changeset
283 void
kono
parents:
diff changeset
284 set_sanitized_sections (const char *sections)
kono
parents:
diff changeset
285 {
kono
parents:
diff changeset
286 char *pat;
kono
parents:
diff changeset
287 unsigned i;
kono
parents:
diff changeset
288 FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
kono
parents:
diff changeset
289 free (pat);
kono
parents:
diff changeset
290 sanitized_sections.truncate (0);
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 for (const char *s = sections; *s; )
kono
parents:
diff changeset
293 {
kono
parents:
diff changeset
294 const char *end;
kono
parents:
diff changeset
295 for (end = s; *end && *end != ','; ++end);
kono
parents:
diff changeset
296 size_t len = end - s;
kono
parents:
diff changeset
297 sanitized_sections.safe_push (xstrndup (s, len));
kono
parents:
diff changeset
298 s = *end ? end + 1 : end;
kono
parents:
diff changeset
299 }
kono
parents:
diff changeset
300 }
kono
parents:
diff changeset
301
kono
parents:
diff changeset
302 bool
kono
parents:
diff changeset
303 asan_mark_p (gimple *stmt, enum asan_mark_flags flag)
kono
parents:
diff changeset
304 {
kono
parents:
diff changeset
305 return (gimple_call_internal_p (stmt, IFN_ASAN_MARK)
kono
parents:
diff changeset
306 && tree_to_uhwi (gimple_call_arg (stmt, 0)) == flag);
kono
parents:
diff changeset
307 }
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 bool
kono
parents:
diff changeset
310 asan_sanitize_stack_p (void)
kono
parents:
diff changeset
311 {
kono
parents:
diff changeset
312 return (sanitize_flags_p (SANITIZE_ADDRESS) && ASAN_STACK);
kono
parents:
diff changeset
313 }
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315 bool
kono
parents:
diff changeset
316 asan_sanitize_allocas_p (void)
kono
parents:
diff changeset
317 {
kono
parents:
diff changeset
318 return (asan_sanitize_stack_p () && ASAN_PROTECT_ALLOCAS);
kono
parents:
diff changeset
319 }
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321 /* Checks whether section SEC should be sanitized. */
kono
parents:
diff changeset
322
kono
parents:
diff changeset
323 static bool
kono
parents:
diff changeset
324 section_sanitized_p (const char *sec)
kono
parents:
diff changeset
325 {
kono
parents:
diff changeset
326 char *pat;
kono
parents:
diff changeset
327 unsigned i;
kono
parents:
diff changeset
328 FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
kono
parents:
diff changeset
329 if (fnmatch (pat, sec, FNM_PERIOD) == 0)
kono
parents:
diff changeset
330 return true;
kono
parents:
diff changeset
331 return false;
kono
parents:
diff changeset
332 }
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 /* Returns Asan shadow offset. */
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 static unsigned HOST_WIDE_INT
kono
parents:
diff changeset
337 asan_shadow_offset ()
kono
parents:
diff changeset
338 {
kono
parents:
diff changeset
339 if (!asan_shadow_offset_computed)
kono
parents:
diff changeset
340 {
kono
parents:
diff changeset
341 asan_shadow_offset_computed = true;
kono
parents:
diff changeset
342 asan_shadow_offset_value = targetm.asan_shadow_offset ();
kono
parents:
diff changeset
343 }
kono
parents:
diff changeset
344 return asan_shadow_offset_value;
kono
parents:
diff changeset
345 }
kono
parents:
diff changeset
346
kono
parents:
diff changeset
347 alias_set_type asan_shadow_set = -1;
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349 /* Pointer types to 1, 2 or 4 byte integers in shadow memory. A separate
kono
parents:
diff changeset
350 alias set is used for all shadow memory accesses. */
kono
parents:
diff changeset
351 static GTY(()) tree shadow_ptr_types[3];
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 /* Decl for __asan_option_detect_stack_use_after_return. */
kono
parents:
diff changeset
354 static GTY(()) tree asan_detect_stack_use_after_return;
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 /* Hashtable support for memory references used by gimple
kono
parents:
diff changeset
357 statements. */
kono
parents:
diff changeset
358
kono
parents:
diff changeset
359 /* This type represents a reference to a memory region. */
kono
parents:
diff changeset
360 struct asan_mem_ref
kono
parents:
diff changeset
361 {
kono
parents:
diff changeset
362 /* The expression of the beginning of the memory region. */
kono
parents:
diff changeset
363 tree start;
kono
parents:
diff changeset
364
kono
parents:
diff changeset
365 /* The size of the access. */
kono
parents:
diff changeset
366 HOST_WIDE_INT access_size;
kono
parents:
diff changeset
367 };
kono
parents:
diff changeset
368
kono
parents:
diff changeset
369 object_allocator <asan_mem_ref> asan_mem_ref_pool ("asan_mem_ref");
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 /* Initializes an instance of asan_mem_ref. */
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 static void
kono
parents:
diff changeset
374 asan_mem_ref_init (asan_mem_ref *ref, tree start, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
375 {
kono
parents:
diff changeset
376 ref->start = start;
kono
parents:
diff changeset
377 ref->access_size = access_size;
kono
parents:
diff changeset
378 }
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 /* Allocates memory for an instance of asan_mem_ref into the memory
kono
parents:
diff changeset
381 pool returned by asan_mem_ref_get_alloc_pool and initialize it.
kono
parents:
diff changeset
382 START is the address of (or the expression pointing to) the
kono
parents:
diff changeset
383 beginning of memory reference. ACCESS_SIZE is the size of the
kono
parents:
diff changeset
384 access to the referenced memory. */
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 static asan_mem_ref*
kono
parents:
diff changeset
387 asan_mem_ref_new (tree start, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
388 {
kono
parents:
diff changeset
389 asan_mem_ref *ref = asan_mem_ref_pool.allocate ();
kono
parents:
diff changeset
390
kono
parents:
diff changeset
391 asan_mem_ref_init (ref, start, access_size);
kono
parents:
diff changeset
392 return ref;
kono
parents:
diff changeset
393 }
kono
parents:
diff changeset
394
kono
parents:
diff changeset
395 /* This builds and returns a pointer to the end of the memory region
kono
parents:
diff changeset
396 that starts at START and of length LEN. */
kono
parents:
diff changeset
397
kono
parents:
diff changeset
398 tree
kono
parents:
diff changeset
399 asan_mem_ref_get_end (tree start, tree len)
kono
parents:
diff changeset
400 {
kono
parents:
diff changeset
401 if (len == NULL_TREE || integer_zerop (len))
kono
parents:
diff changeset
402 return start;
kono
parents:
diff changeset
403
kono
parents:
diff changeset
404 if (!ptrofftype_p (len))
kono
parents:
diff changeset
405 len = convert_to_ptrofftype (len);
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (start), start, len);
kono
parents:
diff changeset
408 }
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410 /* Return a tree expression that represents the end of the referenced
kono
parents:
diff changeset
411 memory region. Beware that this function can actually build a new
kono
parents:
diff changeset
412 tree expression. */
kono
parents:
diff changeset
413
kono
parents:
diff changeset
414 tree
kono
parents:
diff changeset
415 asan_mem_ref_get_end (const asan_mem_ref *ref, tree len)
kono
parents:
diff changeset
416 {
kono
parents:
diff changeset
417 return asan_mem_ref_get_end (ref->start, len);
kono
parents:
diff changeset
418 }
kono
parents:
diff changeset
419
kono
parents:
diff changeset
420 struct asan_mem_ref_hasher : nofree_ptr_hash <asan_mem_ref>
kono
parents:
diff changeset
421 {
kono
parents:
diff changeset
422 static inline hashval_t hash (const asan_mem_ref *);
kono
parents:
diff changeset
423 static inline bool equal (const asan_mem_ref *, const asan_mem_ref *);
kono
parents:
diff changeset
424 };
kono
parents:
diff changeset
425
kono
parents:
diff changeset
426 /* Hash a memory reference. */
kono
parents:
diff changeset
427
kono
parents:
diff changeset
428 inline hashval_t
kono
parents:
diff changeset
429 asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref)
kono
parents:
diff changeset
430 {
kono
parents:
diff changeset
431 return iterative_hash_expr (mem_ref->start, 0);
kono
parents:
diff changeset
432 }
kono
parents:
diff changeset
433
kono
parents:
diff changeset
434 /* Compare two memory references. We accept the length of either
kono
parents:
diff changeset
435 memory references to be NULL_TREE. */
kono
parents:
diff changeset
436
kono
parents:
diff changeset
437 inline bool
kono
parents:
diff changeset
438 asan_mem_ref_hasher::equal (const asan_mem_ref *m1,
kono
parents:
diff changeset
439 const asan_mem_ref *m2)
kono
parents:
diff changeset
440 {
kono
parents:
diff changeset
441 return operand_equal_p (m1->start, m2->start, 0);
kono
parents:
diff changeset
442 }
kono
parents:
diff changeset
443
kono
parents:
diff changeset
444 static hash_table<asan_mem_ref_hasher> *asan_mem_ref_ht;
kono
parents:
diff changeset
445
kono
parents:
diff changeset
446 /* Returns a reference to the hash table containing memory references.
kono
parents:
diff changeset
447 This function ensures that the hash table is created. Note that
kono
parents:
diff changeset
448 this hash table is updated by the function
kono
parents:
diff changeset
449 update_mem_ref_hash_table. */
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 static hash_table<asan_mem_ref_hasher> *
kono
parents:
diff changeset
452 get_mem_ref_hash_table ()
kono
parents:
diff changeset
453 {
kono
parents:
diff changeset
454 if (!asan_mem_ref_ht)
kono
parents:
diff changeset
455 asan_mem_ref_ht = new hash_table<asan_mem_ref_hasher> (10);
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 return asan_mem_ref_ht;
kono
parents:
diff changeset
458 }
kono
parents:
diff changeset
459
kono
parents:
diff changeset
460 /* Clear all entries from the memory references hash table. */
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462 static void
kono
parents:
diff changeset
463 empty_mem_ref_hash_table ()
kono
parents:
diff changeset
464 {
kono
parents:
diff changeset
465 if (asan_mem_ref_ht)
kono
parents:
diff changeset
466 asan_mem_ref_ht->empty ();
kono
parents:
diff changeset
467 }
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 /* Free the memory references hash table. */
kono
parents:
diff changeset
470
kono
parents:
diff changeset
471 static void
kono
parents:
diff changeset
472 free_mem_ref_resources ()
kono
parents:
diff changeset
473 {
kono
parents:
diff changeset
474 delete asan_mem_ref_ht;
kono
parents:
diff changeset
475 asan_mem_ref_ht = NULL;
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 asan_mem_ref_pool.release ();
kono
parents:
diff changeset
478 }
kono
parents:
diff changeset
479
kono
parents:
diff changeset
480 /* Return true iff the memory reference REF has been instrumented. */
kono
parents:
diff changeset
481
kono
parents:
diff changeset
482 static bool
kono
parents:
diff changeset
483 has_mem_ref_been_instrumented (tree ref, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
484 {
kono
parents:
diff changeset
485 asan_mem_ref r;
kono
parents:
diff changeset
486 asan_mem_ref_init (&r, ref, access_size);
kono
parents:
diff changeset
487
kono
parents:
diff changeset
488 asan_mem_ref *saved_ref = get_mem_ref_hash_table ()->find (&r);
kono
parents:
diff changeset
489 return saved_ref && saved_ref->access_size >= access_size;
kono
parents:
diff changeset
490 }
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 /* Return true iff the memory reference REF has been instrumented. */
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 static bool
kono
parents:
diff changeset
495 has_mem_ref_been_instrumented (const asan_mem_ref *ref)
kono
parents:
diff changeset
496 {
kono
parents:
diff changeset
497 return has_mem_ref_been_instrumented (ref->start, ref->access_size);
kono
parents:
diff changeset
498 }
kono
parents:
diff changeset
499
kono
parents:
diff changeset
500 /* Return true iff access to memory region starting at REF and of
kono
parents:
diff changeset
501 length LEN has been instrumented. */
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 static bool
kono
parents:
diff changeset
504 has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
kono
parents:
diff changeset
505 {
kono
parents:
diff changeset
506 HOST_WIDE_INT size_in_bytes
kono
parents:
diff changeset
507 = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 return size_in_bytes != -1
kono
parents:
diff changeset
510 && has_mem_ref_been_instrumented (ref->start, size_in_bytes);
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 /* Set REF to the memory reference present in a gimple assignment
kono
parents:
diff changeset
514 ASSIGNMENT. Return true upon successful completion, false
kono
parents:
diff changeset
515 otherwise. */
kono
parents:
diff changeset
516
kono
parents:
diff changeset
517 static bool
kono
parents:
diff changeset
518 get_mem_ref_of_assignment (const gassign *assignment,
kono
parents:
diff changeset
519 asan_mem_ref *ref,
kono
parents:
diff changeset
520 bool *ref_is_store)
kono
parents:
diff changeset
521 {
kono
parents:
diff changeset
522 gcc_assert (gimple_assign_single_p (assignment));
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 if (gimple_store_p (assignment)
kono
parents:
diff changeset
525 && !gimple_clobber_p (assignment))
kono
parents:
diff changeset
526 {
kono
parents:
diff changeset
527 ref->start = gimple_assign_lhs (assignment);
kono
parents:
diff changeset
528 *ref_is_store = true;
kono
parents:
diff changeset
529 }
kono
parents:
diff changeset
530 else if (gimple_assign_load_p (assignment))
kono
parents:
diff changeset
531 {
kono
parents:
diff changeset
532 ref->start = gimple_assign_rhs1 (assignment);
kono
parents:
diff changeset
533 *ref_is_store = false;
kono
parents:
diff changeset
534 }
kono
parents:
diff changeset
535 else
kono
parents:
diff changeset
536 return false;
kono
parents:
diff changeset
537
kono
parents:
diff changeset
538 ref->access_size = int_size_in_bytes (TREE_TYPE (ref->start));
kono
parents:
diff changeset
539 return true;
kono
parents:
diff changeset
540 }
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 /* Return address of last allocated dynamic alloca. */
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 static tree
kono
parents:
diff changeset
545 get_last_alloca_addr ()
kono
parents:
diff changeset
546 {
kono
parents:
diff changeset
547 if (last_alloca_addr)
kono
parents:
diff changeset
548 return last_alloca_addr;
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 last_alloca_addr = create_tmp_reg (ptr_type_node, "last_alloca_addr");
kono
parents:
diff changeset
551 gassign *g = gimple_build_assign (last_alloca_addr, null_pointer_node);
kono
parents:
diff changeset
552 edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
kono
parents:
diff changeset
553 gsi_insert_on_edge_immediate (e, g);
kono
parents:
diff changeset
554 return last_alloca_addr;
kono
parents:
diff changeset
555 }
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 /* Insert __asan_allocas_unpoison (top, bottom) call after
kono
parents:
diff changeset
558 __builtin_stack_restore (new_sp) call.
kono
parents:
diff changeset
559 The pseudocode of this routine should look like this:
kono
parents:
diff changeset
560 __builtin_stack_restore (new_sp);
kono
parents:
diff changeset
561 top = last_alloca_addr;
kono
parents:
diff changeset
562 bot = new_sp;
kono
parents:
diff changeset
563 __asan_allocas_unpoison (top, bot);
kono
parents:
diff changeset
564 last_alloca_addr = new_sp;
kono
parents:
diff changeset
565 In general, we can't use new_sp as bot parameter because on some
kono
parents:
diff changeset
566 architectures SP has non zero offset from dynamic stack area. Moreover, on
kono
parents:
diff changeset
567 some architectures this offset (STACK_DYNAMIC_OFFSET) becomes known for each
kono
parents:
diff changeset
568 particular function only after all callees were expanded to rtl.
kono
parents:
diff changeset
569 The most noticeable example is PowerPC{,64}, see
kono
parents:
diff changeset
570 http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#DYNAM-STACK.
kono
parents:
diff changeset
571 To overcome the issue we use following trick: pass new_sp as a second
kono
parents:
diff changeset
572 parameter to __asan_allocas_unpoison and rewrite it during expansion with
kono
parents:
diff changeset
573 virtual_dynamic_stack_rtx later in expand_asan_emit_allocas_unpoison
kono
parents:
diff changeset
574 function.
kono
parents:
diff changeset
575 */
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 static void
kono
parents:
diff changeset
578 handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
kono
parents:
diff changeset
579 {
kono
parents:
diff changeset
580 if (!iter || !asan_sanitize_allocas_p ())
kono
parents:
diff changeset
581 return;
kono
parents:
diff changeset
582
kono
parents:
diff changeset
583 tree last_alloca = get_last_alloca_addr ();
kono
parents:
diff changeset
584 tree restored_stack = gimple_call_arg (call, 0);
kono
parents:
diff changeset
585 tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
kono
parents:
diff changeset
586 gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
kono
parents:
diff changeset
587 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
588 g = gimple_build_assign (last_alloca, restored_stack);
kono
parents:
diff changeset
589 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
590 }
kono
parents:
diff changeset
591
kono
parents:
diff changeset
592 /* Deploy and poison redzones around __builtin_alloca call. To do this, we
kono
parents:
diff changeset
593 should replace this call with another one with changed parameters and
kono
parents:
diff changeset
594 replace all its uses with new address, so
kono
parents:
diff changeset
595 addr = __builtin_alloca (old_size, align);
kono
parents:
diff changeset
596 is replaced by
kono
parents:
diff changeset
597 left_redzone_size = max (align, ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
598 Following two statements are optimized out if we know that
kono
parents:
diff changeset
599 old_size & (ASAN_RED_ZONE_SIZE - 1) == 0, i.e. alloca doesn't need partial
kono
parents:
diff changeset
600 redzone.
kono
parents:
diff changeset
601 misalign = old_size & (ASAN_RED_ZONE_SIZE - 1);
kono
parents:
diff changeset
602 partial_redzone_size = ASAN_RED_ZONE_SIZE - misalign;
kono
parents:
diff changeset
603 right_redzone_size = ASAN_RED_ZONE_SIZE;
kono
parents:
diff changeset
604 additional_size = left_redzone_size + partial_redzone_size +
kono
parents:
diff changeset
605 right_redzone_size;
kono
parents:
diff changeset
606 new_size = old_size + additional_size;
kono
parents:
diff changeset
607 new_alloca = __builtin_alloca (new_size, max (align, 32))
kono
parents:
diff changeset
608 __asan_alloca_poison (new_alloca, old_size)
kono
parents:
diff changeset
609 addr = new_alloca + max (align, ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
610 last_alloca_addr = new_alloca;
kono
parents:
diff changeset
611 ADDITIONAL_SIZE is added to make new memory allocation contain not only
kono
parents:
diff changeset
612 requested memory, but also left, partial and right redzones as well as some
kono
parents:
diff changeset
613 additional space, required by alignment. */
kono
parents:
diff changeset
614
kono
parents:
diff changeset
615 static void
kono
parents:
diff changeset
616 handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
kono
parents:
diff changeset
617 {
kono
parents:
diff changeset
618 if (!iter || !asan_sanitize_allocas_p ())
kono
parents:
diff changeset
619 return;
kono
parents:
diff changeset
620
kono
parents:
diff changeset
621 gassign *g;
kono
parents:
diff changeset
622 gcall *gg;
kono
parents:
diff changeset
623 const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
kono
parents:
diff changeset
624
kono
parents:
diff changeset
625 tree last_alloca = get_last_alloca_addr ();
kono
parents:
diff changeset
626 tree callee = gimple_call_fndecl (call);
kono
parents:
diff changeset
627 tree old_size = gimple_call_arg (call, 0);
kono
parents:
diff changeset
628 tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
kono
parents:
diff changeset
629 : ptr_type_node;
kono
parents:
diff changeset
630 tree partial_size = NULL_TREE;
kono
parents:
diff changeset
631 unsigned int align
kono
parents:
diff changeset
632 = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
kono
parents:
diff changeset
633 ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 /* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
kono
parents:
diff changeset
636 bytes of allocated space. Otherwise, align alloca to ASAN_RED_ZONE_SIZE
kono
parents:
diff changeset
637 manually. */
kono
parents:
diff changeset
638 align = MAX (align, ASAN_RED_ZONE_SIZE * BITS_PER_UNIT);
kono
parents:
diff changeset
639
kono
parents:
diff changeset
640 tree alloca_rz_mask = build_int_cst (size_type_node, redzone_mask);
kono
parents:
diff changeset
641 tree redzone_size = build_int_cst (size_type_node, ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
642
kono
parents:
diff changeset
643 /* Extract lower bits from old_size. */
kono
parents:
diff changeset
644 wide_int size_nonzero_bits = get_nonzero_bits (old_size);
kono
parents:
diff changeset
645 wide_int rz_mask
kono
parents:
diff changeset
646 = wi::uhwi (redzone_mask, wi::get_precision (size_nonzero_bits));
kono
parents:
diff changeset
647 wide_int old_size_lower_bits = wi::bit_and (size_nonzero_bits, rz_mask);
kono
parents:
diff changeset
648
kono
parents:
diff changeset
649 /* If alloca size is aligned to ASAN_RED_ZONE_SIZE, we don't need partial
kono
parents:
diff changeset
650 redzone. Otherwise, compute its size here. */
kono
parents:
diff changeset
651 if (wi::ne_p (old_size_lower_bits, 0))
kono
parents:
diff changeset
652 {
kono
parents:
diff changeset
653 /* misalign = size & (ASAN_RED_ZONE_SIZE - 1)
kono
parents:
diff changeset
654 partial_size = ASAN_RED_ZONE_SIZE - misalign. */
kono
parents:
diff changeset
655 g = gimple_build_assign (make_ssa_name (size_type_node, NULL),
kono
parents:
diff changeset
656 BIT_AND_EXPR, old_size, alloca_rz_mask);
kono
parents:
diff changeset
657 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
658 tree misalign = gimple_assign_lhs (g);
kono
parents:
diff changeset
659 g = gimple_build_assign (make_ssa_name (size_type_node, NULL), MINUS_EXPR,
kono
parents:
diff changeset
660 redzone_size, misalign);
kono
parents:
diff changeset
661 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
662 partial_size = gimple_assign_lhs (g);
kono
parents:
diff changeset
663 }
kono
parents:
diff changeset
664
kono
parents:
diff changeset
665 /* additional_size = align + ASAN_RED_ZONE_SIZE. */
kono
parents:
diff changeset
666 tree additional_size = build_int_cst (size_type_node, align / BITS_PER_UNIT
kono
parents:
diff changeset
667 + ASAN_RED_ZONE_SIZE);
kono
parents:
diff changeset
668 /* If alloca has partial redzone, include it to additional_size too. */
kono
parents:
diff changeset
669 if (partial_size)
kono
parents:
diff changeset
670 {
kono
parents:
diff changeset
671 /* additional_size += partial_size. */
kono
parents:
diff changeset
672 g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
kono
parents:
diff changeset
673 partial_size, additional_size);
kono
parents:
diff changeset
674 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
675 additional_size = gimple_assign_lhs (g);
kono
parents:
diff changeset
676 }
kono
parents:
diff changeset
677
kono
parents:
diff changeset
678 /* new_size = old_size + additional_size. */
kono
parents:
diff changeset
679 g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR, old_size,
kono
parents:
diff changeset
680 additional_size);
kono
parents:
diff changeset
681 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
682 tree new_size = gimple_assign_lhs (g);
kono
parents:
diff changeset
683
kono
parents:
diff changeset
684 /* Build new __builtin_alloca call:
kono
parents:
diff changeset
685 new_alloca_with_rz = __builtin_alloca (new_size, align). */
kono
parents:
diff changeset
686 tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
kono
parents:
diff changeset
687 gg = gimple_build_call (fn, 2, new_size,
kono
parents:
diff changeset
688 build_int_cst (size_type_node, align));
kono
parents:
diff changeset
689 tree new_alloca_with_rz = make_ssa_name (ptr_type, gg);
kono
parents:
diff changeset
690 gimple_call_set_lhs (gg, new_alloca_with_rz);
kono
parents:
diff changeset
691 gsi_insert_before (iter, gg, GSI_SAME_STMT);
kono
parents:
diff changeset
692
kono
parents:
diff changeset
693 /* new_alloca = new_alloca_with_rz + align. */
kono
parents:
diff changeset
694 g = gimple_build_assign (make_ssa_name (ptr_type), POINTER_PLUS_EXPR,
kono
parents:
diff changeset
695 new_alloca_with_rz,
kono
parents:
diff changeset
696 build_int_cst (size_type_node,
kono
parents:
diff changeset
697 align / BITS_PER_UNIT));
kono
parents:
diff changeset
698 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
699 tree new_alloca = gimple_assign_lhs (g);
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 /* Poison newly created alloca redzones:
kono
parents:
diff changeset
702 __asan_alloca_poison (new_alloca, old_size). */
kono
parents:
diff changeset
703 fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCA_POISON);
kono
parents:
diff changeset
704 gg = gimple_build_call (fn, 2, new_alloca, old_size);
kono
parents:
diff changeset
705 gsi_insert_before (iter, gg, GSI_SAME_STMT);
kono
parents:
diff changeset
706
kono
parents:
diff changeset
707 /* Save new_alloca_with_rz value into last_alloca to use it during
kono
parents:
diff changeset
708 allocas unpoisoning. */
kono
parents:
diff changeset
709 g = gimple_build_assign (last_alloca, new_alloca_with_rz);
kono
parents:
diff changeset
710 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712 /* Finally, replace old alloca ptr with NEW_ALLOCA. */
kono
parents:
diff changeset
713 replace_call_with_value (iter, new_alloca);
kono
parents:
diff changeset
714 }
kono
parents:
diff changeset
715
kono
parents:
diff changeset
716 /* Return the memory references contained in a gimple statement
kono
parents:
diff changeset
717 representing a builtin call that has to do with memory access. */
kono
parents:
diff changeset
718
kono
parents:
diff changeset
719 static bool
kono
parents:
diff changeset
720 get_mem_refs_of_builtin_call (gcall *call,
kono
parents:
diff changeset
721 asan_mem_ref *src0,
kono
parents:
diff changeset
722 tree *src0_len,
kono
parents:
diff changeset
723 bool *src0_is_store,
kono
parents:
diff changeset
724 asan_mem_ref *src1,
kono
parents:
diff changeset
725 tree *src1_len,
kono
parents:
diff changeset
726 bool *src1_is_store,
kono
parents:
diff changeset
727 asan_mem_ref *dst,
kono
parents:
diff changeset
728 tree *dst_len,
kono
parents:
diff changeset
729 bool *dst_is_store,
kono
parents:
diff changeset
730 bool *dest_is_deref,
kono
parents:
diff changeset
731 bool *intercepted_p,
kono
parents:
diff changeset
732 gimple_stmt_iterator *iter = NULL)
kono
parents:
diff changeset
733 {
kono
parents:
diff changeset
734 gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
kono
parents:
diff changeset
735
kono
parents:
diff changeset
736 tree callee = gimple_call_fndecl (call);
kono
parents:
diff changeset
737 tree source0 = NULL_TREE, source1 = NULL_TREE,
kono
parents:
diff changeset
738 dest = NULL_TREE, len = NULL_TREE;
kono
parents:
diff changeset
739 bool is_store = true, got_reference_p = false;
kono
parents:
diff changeset
740 HOST_WIDE_INT access_size = 1;
kono
parents:
diff changeset
741
kono
parents:
diff changeset
742 *intercepted_p = asan_intercepted_p ((DECL_FUNCTION_CODE (callee)));
kono
parents:
diff changeset
743
kono
parents:
diff changeset
744 switch (DECL_FUNCTION_CODE (callee))
kono
parents:
diff changeset
745 {
kono
parents:
diff changeset
746 /* (s, s, n) style memops. */
kono
parents:
diff changeset
747 case BUILT_IN_BCMP:
kono
parents:
diff changeset
748 case BUILT_IN_MEMCMP:
kono
parents:
diff changeset
749 source0 = gimple_call_arg (call, 0);
kono
parents:
diff changeset
750 source1 = gimple_call_arg (call, 1);
kono
parents:
diff changeset
751 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
752 break;
kono
parents:
diff changeset
753
kono
parents:
diff changeset
754 /* (src, dest, n) style memops. */
kono
parents:
diff changeset
755 case BUILT_IN_BCOPY:
kono
parents:
diff changeset
756 source0 = gimple_call_arg (call, 0);
kono
parents:
diff changeset
757 dest = gimple_call_arg (call, 1);
kono
parents:
diff changeset
758 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
759 break;
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 /* (dest, src, n) style memops. */
kono
parents:
diff changeset
762 case BUILT_IN_MEMCPY:
kono
parents:
diff changeset
763 case BUILT_IN_MEMCPY_CHK:
kono
parents:
diff changeset
764 case BUILT_IN_MEMMOVE:
kono
parents:
diff changeset
765 case BUILT_IN_MEMMOVE_CHK:
kono
parents:
diff changeset
766 case BUILT_IN_MEMPCPY:
kono
parents:
diff changeset
767 case BUILT_IN_MEMPCPY_CHK:
kono
parents:
diff changeset
768 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
769 source0 = gimple_call_arg (call, 1);
kono
parents:
diff changeset
770 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
771 break;
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 /* (dest, n) style memops. */
kono
parents:
diff changeset
774 case BUILT_IN_BZERO:
kono
parents:
diff changeset
775 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
776 len = gimple_call_arg (call, 1);
kono
parents:
diff changeset
777 break;
kono
parents:
diff changeset
778
kono
parents:
diff changeset
779 /* (dest, x, n) style memops*/
kono
parents:
diff changeset
780 case BUILT_IN_MEMSET:
kono
parents:
diff changeset
781 case BUILT_IN_MEMSET_CHK:
kono
parents:
diff changeset
782 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
783 len = gimple_call_arg (call, 2);
kono
parents:
diff changeset
784 break;
kono
parents:
diff changeset
785
kono
parents:
diff changeset
786 case BUILT_IN_STRLEN:
kono
parents:
diff changeset
787 source0 = gimple_call_arg (call, 0);
kono
parents:
diff changeset
788 len = gimple_call_lhs (call);
kono
parents:
diff changeset
789 break;
kono
parents:
diff changeset
790
kono
parents:
diff changeset
791 case BUILT_IN_STACK_RESTORE:
kono
parents:
diff changeset
792 handle_builtin_stack_restore (call, iter);
kono
parents:
diff changeset
793 break;
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 CASE_BUILT_IN_ALLOCA:
kono
parents:
diff changeset
796 handle_builtin_alloca (call, iter);
kono
parents:
diff changeset
797 break;
kono
parents:
diff changeset
798 /* And now the __atomic* and __sync builtins.
kono
parents:
diff changeset
799 These are handled differently from the classical memory memory
kono
parents:
diff changeset
800 access builtins above. */
kono
parents:
diff changeset
801
kono
parents:
diff changeset
802 case BUILT_IN_ATOMIC_LOAD_1:
kono
parents:
diff changeset
803 is_store = false;
kono
parents:
diff changeset
804 /* FALLTHRU */
kono
parents:
diff changeset
805 case BUILT_IN_SYNC_FETCH_AND_ADD_1:
kono
parents:
diff changeset
806 case BUILT_IN_SYNC_FETCH_AND_SUB_1:
kono
parents:
diff changeset
807 case BUILT_IN_SYNC_FETCH_AND_OR_1:
kono
parents:
diff changeset
808 case BUILT_IN_SYNC_FETCH_AND_AND_1:
kono
parents:
diff changeset
809 case BUILT_IN_SYNC_FETCH_AND_XOR_1:
kono
parents:
diff changeset
810 case BUILT_IN_SYNC_FETCH_AND_NAND_1:
kono
parents:
diff changeset
811 case BUILT_IN_SYNC_ADD_AND_FETCH_1:
kono
parents:
diff changeset
812 case BUILT_IN_SYNC_SUB_AND_FETCH_1:
kono
parents:
diff changeset
813 case BUILT_IN_SYNC_OR_AND_FETCH_1:
kono
parents:
diff changeset
814 case BUILT_IN_SYNC_AND_AND_FETCH_1:
kono
parents:
diff changeset
815 case BUILT_IN_SYNC_XOR_AND_FETCH_1:
kono
parents:
diff changeset
816 case BUILT_IN_SYNC_NAND_AND_FETCH_1:
kono
parents:
diff changeset
817 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
kono
parents:
diff changeset
818 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
kono
parents:
diff changeset
819 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
kono
parents:
diff changeset
820 case BUILT_IN_SYNC_LOCK_RELEASE_1:
kono
parents:
diff changeset
821 case BUILT_IN_ATOMIC_EXCHANGE_1:
kono
parents:
diff changeset
822 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
kono
parents:
diff changeset
823 case BUILT_IN_ATOMIC_STORE_1:
kono
parents:
diff changeset
824 case BUILT_IN_ATOMIC_ADD_FETCH_1:
kono
parents:
diff changeset
825 case BUILT_IN_ATOMIC_SUB_FETCH_1:
kono
parents:
diff changeset
826 case BUILT_IN_ATOMIC_AND_FETCH_1:
kono
parents:
diff changeset
827 case BUILT_IN_ATOMIC_NAND_FETCH_1:
kono
parents:
diff changeset
828 case BUILT_IN_ATOMIC_XOR_FETCH_1:
kono
parents:
diff changeset
829 case BUILT_IN_ATOMIC_OR_FETCH_1:
kono
parents:
diff changeset
830 case BUILT_IN_ATOMIC_FETCH_ADD_1:
kono
parents:
diff changeset
831 case BUILT_IN_ATOMIC_FETCH_SUB_1:
kono
parents:
diff changeset
832 case BUILT_IN_ATOMIC_FETCH_AND_1:
kono
parents:
diff changeset
833 case BUILT_IN_ATOMIC_FETCH_NAND_1:
kono
parents:
diff changeset
834 case BUILT_IN_ATOMIC_FETCH_XOR_1:
kono
parents:
diff changeset
835 case BUILT_IN_ATOMIC_FETCH_OR_1:
kono
parents:
diff changeset
836 access_size = 1;
kono
parents:
diff changeset
837 goto do_atomic;
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 case BUILT_IN_ATOMIC_LOAD_2:
kono
parents:
diff changeset
840 is_store = false;
kono
parents:
diff changeset
841 /* FALLTHRU */
kono
parents:
diff changeset
842 case BUILT_IN_SYNC_FETCH_AND_ADD_2:
kono
parents:
diff changeset
843 case BUILT_IN_SYNC_FETCH_AND_SUB_2:
kono
parents:
diff changeset
844 case BUILT_IN_SYNC_FETCH_AND_OR_2:
kono
parents:
diff changeset
845 case BUILT_IN_SYNC_FETCH_AND_AND_2:
kono
parents:
diff changeset
846 case BUILT_IN_SYNC_FETCH_AND_XOR_2:
kono
parents:
diff changeset
847 case BUILT_IN_SYNC_FETCH_AND_NAND_2:
kono
parents:
diff changeset
848 case BUILT_IN_SYNC_ADD_AND_FETCH_2:
kono
parents:
diff changeset
849 case BUILT_IN_SYNC_SUB_AND_FETCH_2:
kono
parents:
diff changeset
850 case BUILT_IN_SYNC_OR_AND_FETCH_2:
kono
parents:
diff changeset
851 case BUILT_IN_SYNC_AND_AND_FETCH_2:
kono
parents:
diff changeset
852 case BUILT_IN_SYNC_XOR_AND_FETCH_2:
kono
parents:
diff changeset
853 case BUILT_IN_SYNC_NAND_AND_FETCH_2:
kono
parents:
diff changeset
854 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
kono
parents:
diff changeset
855 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
kono
parents:
diff changeset
856 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
kono
parents:
diff changeset
857 case BUILT_IN_SYNC_LOCK_RELEASE_2:
kono
parents:
diff changeset
858 case BUILT_IN_ATOMIC_EXCHANGE_2:
kono
parents:
diff changeset
859 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
kono
parents:
diff changeset
860 case BUILT_IN_ATOMIC_STORE_2:
kono
parents:
diff changeset
861 case BUILT_IN_ATOMIC_ADD_FETCH_2:
kono
parents:
diff changeset
862 case BUILT_IN_ATOMIC_SUB_FETCH_2:
kono
parents:
diff changeset
863 case BUILT_IN_ATOMIC_AND_FETCH_2:
kono
parents:
diff changeset
864 case BUILT_IN_ATOMIC_NAND_FETCH_2:
kono
parents:
diff changeset
865 case BUILT_IN_ATOMIC_XOR_FETCH_2:
kono
parents:
diff changeset
866 case BUILT_IN_ATOMIC_OR_FETCH_2:
kono
parents:
diff changeset
867 case BUILT_IN_ATOMIC_FETCH_ADD_2:
kono
parents:
diff changeset
868 case BUILT_IN_ATOMIC_FETCH_SUB_2:
kono
parents:
diff changeset
869 case BUILT_IN_ATOMIC_FETCH_AND_2:
kono
parents:
diff changeset
870 case BUILT_IN_ATOMIC_FETCH_NAND_2:
kono
parents:
diff changeset
871 case BUILT_IN_ATOMIC_FETCH_XOR_2:
kono
parents:
diff changeset
872 case BUILT_IN_ATOMIC_FETCH_OR_2:
kono
parents:
diff changeset
873 access_size = 2;
kono
parents:
diff changeset
874 goto do_atomic;
kono
parents:
diff changeset
875
kono
parents:
diff changeset
876 case BUILT_IN_ATOMIC_LOAD_4:
kono
parents:
diff changeset
877 is_store = false;
kono
parents:
diff changeset
878 /* FALLTHRU */
kono
parents:
diff changeset
879 case BUILT_IN_SYNC_FETCH_AND_ADD_4:
kono
parents:
diff changeset
880 case BUILT_IN_SYNC_FETCH_AND_SUB_4:
kono
parents:
diff changeset
881 case BUILT_IN_SYNC_FETCH_AND_OR_4:
kono
parents:
diff changeset
882 case BUILT_IN_SYNC_FETCH_AND_AND_4:
kono
parents:
diff changeset
883 case BUILT_IN_SYNC_FETCH_AND_XOR_4:
kono
parents:
diff changeset
884 case BUILT_IN_SYNC_FETCH_AND_NAND_4:
kono
parents:
diff changeset
885 case BUILT_IN_SYNC_ADD_AND_FETCH_4:
kono
parents:
diff changeset
886 case BUILT_IN_SYNC_SUB_AND_FETCH_4:
kono
parents:
diff changeset
887 case BUILT_IN_SYNC_OR_AND_FETCH_4:
kono
parents:
diff changeset
888 case BUILT_IN_SYNC_AND_AND_FETCH_4:
kono
parents:
diff changeset
889 case BUILT_IN_SYNC_XOR_AND_FETCH_4:
kono
parents:
diff changeset
890 case BUILT_IN_SYNC_NAND_AND_FETCH_4:
kono
parents:
diff changeset
891 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
kono
parents:
diff changeset
892 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
kono
parents:
diff changeset
893 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
kono
parents:
diff changeset
894 case BUILT_IN_SYNC_LOCK_RELEASE_4:
kono
parents:
diff changeset
895 case BUILT_IN_ATOMIC_EXCHANGE_4:
kono
parents:
diff changeset
896 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
kono
parents:
diff changeset
897 case BUILT_IN_ATOMIC_STORE_4:
kono
parents:
diff changeset
898 case BUILT_IN_ATOMIC_ADD_FETCH_4:
kono
parents:
diff changeset
899 case BUILT_IN_ATOMIC_SUB_FETCH_4:
kono
parents:
diff changeset
900 case BUILT_IN_ATOMIC_AND_FETCH_4:
kono
parents:
diff changeset
901 case BUILT_IN_ATOMIC_NAND_FETCH_4:
kono
parents:
diff changeset
902 case BUILT_IN_ATOMIC_XOR_FETCH_4:
kono
parents:
diff changeset
903 case BUILT_IN_ATOMIC_OR_FETCH_4:
kono
parents:
diff changeset
904 case BUILT_IN_ATOMIC_FETCH_ADD_4:
kono
parents:
diff changeset
905 case BUILT_IN_ATOMIC_FETCH_SUB_4:
kono
parents:
diff changeset
906 case BUILT_IN_ATOMIC_FETCH_AND_4:
kono
parents:
diff changeset
907 case BUILT_IN_ATOMIC_FETCH_NAND_4:
kono
parents:
diff changeset
908 case BUILT_IN_ATOMIC_FETCH_XOR_4:
kono
parents:
diff changeset
909 case BUILT_IN_ATOMIC_FETCH_OR_4:
kono
parents:
diff changeset
910 access_size = 4;
kono
parents:
diff changeset
911 goto do_atomic;
kono
parents:
diff changeset
912
kono
parents:
diff changeset
913 case BUILT_IN_ATOMIC_LOAD_8:
kono
parents:
diff changeset
914 is_store = false;
kono
parents:
diff changeset
915 /* FALLTHRU */
kono
parents:
diff changeset
916 case BUILT_IN_SYNC_FETCH_AND_ADD_8:
kono
parents:
diff changeset
917 case BUILT_IN_SYNC_FETCH_AND_SUB_8:
kono
parents:
diff changeset
918 case BUILT_IN_SYNC_FETCH_AND_OR_8:
kono
parents:
diff changeset
919 case BUILT_IN_SYNC_FETCH_AND_AND_8:
kono
parents:
diff changeset
920 case BUILT_IN_SYNC_FETCH_AND_XOR_8:
kono
parents:
diff changeset
921 case BUILT_IN_SYNC_FETCH_AND_NAND_8:
kono
parents:
diff changeset
922 case BUILT_IN_SYNC_ADD_AND_FETCH_8:
kono
parents:
diff changeset
923 case BUILT_IN_SYNC_SUB_AND_FETCH_8:
kono
parents:
diff changeset
924 case BUILT_IN_SYNC_OR_AND_FETCH_8:
kono
parents:
diff changeset
925 case BUILT_IN_SYNC_AND_AND_FETCH_8:
kono
parents:
diff changeset
926 case BUILT_IN_SYNC_XOR_AND_FETCH_8:
kono
parents:
diff changeset
927 case BUILT_IN_SYNC_NAND_AND_FETCH_8:
kono
parents:
diff changeset
928 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
kono
parents:
diff changeset
929 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
kono
parents:
diff changeset
930 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
kono
parents:
diff changeset
931 case BUILT_IN_SYNC_LOCK_RELEASE_8:
kono
parents:
diff changeset
932 case BUILT_IN_ATOMIC_EXCHANGE_8:
kono
parents:
diff changeset
933 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
kono
parents:
diff changeset
934 case BUILT_IN_ATOMIC_STORE_8:
kono
parents:
diff changeset
935 case BUILT_IN_ATOMIC_ADD_FETCH_8:
kono
parents:
diff changeset
936 case BUILT_IN_ATOMIC_SUB_FETCH_8:
kono
parents:
diff changeset
937 case BUILT_IN_ATOMIC_AND_FETCH_8:
kono
parents:
diff changeset
938 case BUILT_IN_ATOMIC_NAND_FETCH_8:
kono
parents:
diff changeset
939 case BUILT_IN_ATOMIC_XOR_FETCH_8:
kono
parents:
diff changeset
940 case BUILT_IN_ATOMIC_OR_FETCH_8:
kono
parents:
diff changeset
941 case BUILT_IN_ATOMIC_FETCH_ADD_8:
kono
parents:
diff changeset
942 case BUILT_IN_ATOMIC_FETCH_SUB_8:
kono
parents:
diff changeset
943 case BUILT_IN_ATOMIC_FETCH_AND_8:
kono
parents:
diff changeset
944 case BUILT_IN_ATOMIC_FETCH_NAND_8:
kono
parents:
diff changeset
945 case BUILT_IN_ATOMIC_FETCH_XOR_8:
kono
parents:
diff changeset
946 case BUILT_IN_ATOMIC_FETCH_OR_8:
kono
parents:
diff changeset
947 access_size = 8;
kono
parents:
diff changeset
948 goto do_atomic;
kono
parents:
diff changeset
949
kono
parents:
diff changeset
950 case BUILT_IN_ATOMIC_LOAD_16:
kono
parents:
diff changeset
951 is_store = false;
kono
parents:
diff changeset
952 /* FALLTHRU */
kono
parents:
diff changeset
953 case BUILT_IN_SYNC_FETCH_AND_ADD_16:
kono
parents:
diff changeset
954 case BUILT_IN_SYNC_FETCH_AND_SUB_16:
kono
parents:
diff changeset
955 case BUILT_IN_SYNC_FETCH_AND_OR_16:
kono
parents:
diff changeset
956 case BUILT_IN_SYNC_FETCH_AND_AND_16:
kono
parents:
diff changeset
957 case BUILT_IN_SYNC_FETCH_AND_XOR_16:
kono
parents:
diff changeset
958 case BUILT_IN_SYNC_FETCH_AND_NAND_16:
kono
parents:
diff changeset
959 case BUILT_IN_SYNC_ADD_AND_FETCH_16:
kono
parents:
diff changeset
960 case BUILT_IN_SYNC_SUB_AND_FETCH_16:
kono
parents:
diff changeset
961 case BUILT_IN_SYNC_OR_AND_FETCH_16:
kono
parents:
diff changeset
962 case BUILT_IN_SYNC_AND_AND_FETCH_16:
kono
parents:
diff changeset
963 case BUILT_IN_SYNC_XOR_AND_FETCH_16:
kono
parents:
diff changeset
964 case BUILT_IN_SYNC_NAND_AND_FETCH_16:
kono
parents:
diff changeset
965 case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
kono
parents:
diff changeset
966 case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
kono
parents:
diff changeset
967 case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
kono
parents:
diff changeset
968 case BUILT_IN_SYNC_LOCK_RELEASE_16:
kono
parents:
diff changeset
969 case BUILT_IN_ATOMIC_EXCHANGE_16:
kono
parents:
diff changeset
970 case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
kono
parents:
diff changeset
971 case BUILT_IN_ATOMIC_STORE_16:
kono
parents:
diff changeset
972 case BUILT_IN_ATOMIC_ADD_FETCH_16:
kono
parents:
diff changeset
973 case BUILT_IN_ATOMIC_SUB_FETCH_16:
kono
parents:
diff changeset
974 case BUILT_IN_ATOMIC_AND_FETCH_16:
kono
parents:
diff changeset
975 case BUILT_IN_ATOMIC_NAND_FETCH_16:
kono
parents:
diff changeset
976 case BUILT_IN_ATOMIC_XOR_FETCH_16:
kono
parents:
diff changeset
977 case BUILT_IN_ATOMIC_OR_FETCH_16:
kono
parents:
diff changeset
978 case BUILT_IN_ATOMIC_FETCH_ADD_16:
kono
parents:
diff changeset
979 case BUILT_IN_ATOMIC_FETCH_SUB_16:
kono
parents:
diff changeset
980 case BUILT_IN_ATOMIC_FETCH_AND_16:
kono
parents:
diff changeset
981 case BUILT_IN_ATOMIC_FETCH_NAND_16:
kono
parents:
diff changeset
982 case BUILT_IN_ATOMIC_FETCH_XOR_16:
kono
parents:
diff changeset
983 case BUILT_IN_ATOMIC_FETCH_OR_16:
kono
parents:
diff changeset
984 access_size = 16;
kono
parents:
diff changeset
985 /* FALLTHRU */
kono
parents:
diff changeset
986 do_atomic:
kono
parents:
diff changeset
987 {
kono
parents:
diff changeset
988 dest = gimple_call_arg (call, 0);
kono
parents:
diff changeset
989 /* DEST represents the address of a memory location.
kono
parents:
diff changeset
990 instrument_derefs wants the memory location, so lets
kono
parents:
diff changeset
991 dereference the address DEST before handing it to
kono
parents:
diff changeset
992 instrument_derefs. */
kono
parents:
diff changeset
993 tree type = build_nonstandard_integer_type (access_size
kono
parents:
diff changeset
994 * BITS_PER_UNIT, 1);
kono
parents:
diff changeset
995 dest = build2 (MEM_REF, type, dest,
kono
parents:
diff changeset
996 build_int_cst (build_pointer_type (char_type_node), 0));
kono
parents:
diff changeset
997 break;
kono
parents:
diff changeset
998 }
kono
parents:
diff changeset
999
kono
parents:
diff changeset
1000 default:
kono
parents:
diff changeset
1001 /* The other builtins memory access are not instrumented in this
kono
parents:
diff changeset
1002 function because they either don't have any length parameter,
kono
parents:
diff changeset
1003 or their length parameter is just a limit. */
kono
parents:
diff changeset
1004 break;
kono
parents:
diff changeset
1005 }
kono
parents:
diff changeset
1006
kono
parents:
diff changeset
1007 if (len != NULL_TREE)
kono
parents:
diff changeset
1008 {
kono
parents:
diff changeset
1009 if (source0 != NULL_TREE)
kono
parents:
diff changeset
1010 {
kono
parents:
diff changeset
1011 src0->start = source0;
kono
parents:
diff changeset
1012 src0->access_size = access_size;
kono
parents:
diff changeset
1013 *src0_len = len;
kono
parents:
diff changeset
1014 *src0_is_store = false;
kono
parents:
diff changeset
1015 }
kono
parents:
diff changeset
1016
kono
parents:
diff changeset
1017 if (source1 != NULL_TREE)
kono
parents:
diff changeset
1018 {
kono
parents:
diff changeset
1019 src1->start = source1;
kono
parents:
diff changeset
1020 src1->access_size = access_size;
kono
parents:
diff changeset
1021 *src1_len = len;
kono
parents:
diff changeset
1022 *src1_is_store = false;
kono
parents:
diff changeset
1023 }
kono
parents:
diff changeset
1024
kono
parents:
diff changeset
1025 if (dest != NULL_TREE)
kono
parents:
diff changeset
1026 {
kono
parents:
diff changeset
1027 dst->start = dest;
kono
parents:
diff changeset
1028 dst->access_size = access_size;
kono
parents:
diff changeset
1029 *dst_len = len;
kono
parents:
diff changeset
1030 *dst_is_store = true;
kono
parents:
diff changeset
1031 }
kono
parents:
diff changeset
1032
kono
parents:
diff changeset
1033 got_reference_p = true;
kono
parents:
diff changeset
1034 }
kono
parents:
diff changeset
1035 else if (dest)
kono
parents:
diff changeset
1036 {
kono
parents:
diff changeset
1037 dst->start = dest;
kono
parents:
diff changeset
1038 dst->access_size = access_size;
kono
parents:
diff changeset
1039 *dst_len = NULL_TREE;
kono
parents:
diff changeset
1040 *dst_is_store = is_store;
kono
parents:
diff changeset
1041 *dest_is_deref = true;
kono
parents:
diff changeset
1042 got_reference_p = true;
kono
parents:
diff changeset
1043 }
kono
parents:
diff changeset
1044
kono
parents:
diff changeset
1045 return got_reference_p;
kono
parents:
diff changeset
1046 }
kono
parents:
diff changeset
1047
kono
parents:
diff changeset
1048 /* Return true iff a given gimple statement has been instrumented.
kono
parents:
diff changeset
1049 Note that the statement is "defined" by the memory references it
kono
parents:
diff changeset
1050 contains. */
kono
parents:
diff changeset
1051
kono
parents:
diff changeset
1052 static bool
kono
parents:
diff changeset
1053 has_stmt_been_instrumented_p (gimple *stmt)
kono
parents:
diff changeset
1054 {
kono
parents:
diff changeset
1055 if (gimple_assign_single_p (stmt))
kono
parents:
diff changeset
1056 {
kono
parents:
diff changeset
1057 bool r_is_store;
kono
parents:
diff changeset
1058 asan_mem_ref r;
kono
parents:
diff changeset
1059 asan_mem_ref_init (&r, NULL, 1);
kono
parents:
diff changeset
1060
kono
parents:
diff changeset
1061 if (get_mem_ref_of_assignment (as_a <gassign *> (stmt), &r,
kono
parents:
diff changeset
1062 &r_is_store))
kono
parents:
diff changeset
1063 return has_mem_ref_been_instrumented (&r);
kono
parents:
diff changeset
1064 }
kono
parents:
diff changeset
1065 else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
kono
parents:
diff changeset
1066 {
kono
parents:
diff changeset
1067 asan_mem_ref src0, src1, dest;
kono
parents:
diff changeset
1068 asan_mem_ref_init (&src0, NULL, 1);
kono
parents:
diff changeset
1069 asan_mem_ref_init (&src1, NULL, 1);
kono
parents:
diff changeset
1070 asan_mem_ref_init (&dest, NULL, 1);
kono
parents:
diff changeset
1071
kono
parents:
diff changeset
1072 tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
kono
parents:
diff changeset
1073 bool src0_is_store = false, src1_is_store = false,
kono
parents:
diff changeset
1074 dest_is_store = false, dest_is_deref = false, intercepted_p = true;
kono
parents:
diff changeset
1075 if (get_mem_refs_of_builtin_call (as_a <gcall *> (stmt),
kono
parents:
diff changeset
1076 &src0, &src0_len, &src0_is_store,
kono
parents:
diff changeset
1077 &src1, &src1_len, &src1_is_store,
kono
parents:
diff changeset
1078 &dest, &dest_len, &dest_is_store,
kono
parents:
diff changeset
1079 &dest_is_deref, &intercepted_p))
kono
parents:
diff changeset
1080 {
kono
parents:
diff changeset
1081 if (src0.start != NULL_TREE
kono
parents:
diff changeset
1082 && !has_mem_ref_been_instrumented (&src0, src0_len))
kono
parents:
diff changeset
1083 return false;
kono
parents:
diff changeset
1084
kono
parents:
diff changeset
1085 if (src1.start != NULL_TREE
kono
parents:
diff changeset
1086 && !has_mem_ref_been_instrumented (&src1, src1_len))
kono
parents:
diff changeset
1087 return false;
kono
parents:
diff changeset
1088
kono
parents:
diff changeset
1089 if (dest.start != NULL_TREE
kono
parents:
diff changeset
1090 && !has_mem_ref_been_instrumented (&dest, dest_len))
kono
parents:
diff changeset
1091 return false;
kono
parents:
diff changeset
1092
kono
parents:
diff changeset
1093 return true;
kono
parents:
diff changeset
1094 }
kono
parents:
diff changeset
1095 }
kono
parents:
diff changeset
1096 else if (is_gimple_call (stmt) && gimple_store_p (stmt))
kono
parents:
diff changeset
1097 {
kono
parents:
diff changeset
1098 asan_mem_ref r;
kono
parents:
diff changeset
1099 asan_mem_ref_init (&r, NULL, 1);
kono
parents:
diff changeset
1100
kono
parents:
diff changeset
1101 r.start = gimple_call_lhs (stmt);
kono
parents:
diff changeset
1102 r.access_size = int_size_in_bytes (TREE_TYPE (r.start));
kono
parents:
diff changeset
1103 return has_mem_ref_been_instrumented (&r);
kono
parents:
diff changeset
1104 }
kono
parents:
diff changeset
1105
kono
parents:
diff changeset
1106 return false;
kono
parents:
diff changeset
1107 }
kono
parents:
diff changeset
1108
kono
parents:
diff changeset
1109 /* Insert a memory reference into the hash table. */
kono
parents:
diff changeset
1110
kono
parents:
diff changeset
1111 static void
kono
parents:
diff changeset
1112 update_mem_ref_hash_table (tree ref, HOST_WIDE_INT access_size)
kono
parents:
diff changeset
1113 {
kono
parents:
diff changeset
1114 hash_table<asan_mem_ref_hasher> *ht = get_mem_ref_hash_table ();
kono
parents:
diff changeset
1115
kono
parents:
diff changeset
1116 asan_mem_ref r;
kono
parents:
diff changeset
1117 asan_mem_ref_init (&r, ref, access_size);
kono
parents:
diff changeset
1118
kono
parents:
diff changeset
1119 asan_mem_ref **slot = ht->find_slot (&r, INSERT);
kono
parents:
diff changeset
1120 if (*slot == NULL || (*slot)->access_size < access_size)
kono
parents:
diff changeset
1121 *slot = asan_mem_ref_new (ref, access_size);
kono
parents:
diff changeset
1122 }
kono
parents:
diff changeset
1123
kono
parents:
diff changeset
1124 /* Initialize shadow_ptr_types array. */
kono
parents:
diff changeset
1125
kono
parents:
diff changeset
1126 static void
kono
parents:
diff changeset
1127 asan_init_shadow_ptr_types (void)
kono
parents:
diff changeset
1128 {
kono
parents:
diff changeset
1129 asan_shadow_set = new_alias_set ();
kono
parents:
diff changeset
1130 tree types[3] = { signed_char_type_node, short_integer_type_node,
kono
parents:
diff changeset
1131 integer_type_node };
kono
parents:
diff changeset
1132
kono
parents:
diff changeset
1133 for (unsigned i = 0; i < 3; i++)
kono
parents:
diff changeset
1134 {
kono
parents:
diff changeset
1135 shadow_ptr_types[i] = build_distinct_type_copy (types[i]);
kono
parents:
diff changeset
1136 TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set;
kono
parents:
diff changeset
1137 shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]);
kono
parents:
diff changeset
1138 }
kono
parents:
diff changeset
1139
kono
parents:
diff changeset
1140 initialize_sanitizer_builtins ();
kono
parents:
diff changeset
1141 }
kono
parents:
diff changeset
1142
kono
parents:
diff changeset
1143 /* Create ADDR_EXPR of STRING_CST with the PP pretty printer text. */
kono
parents:
diff changeset
1144
kono
parents:
diff changeset
1145 static tree
kono
parents:
diff changeset
1146 asan_pp_string (pretty_printer *pp)
kono
parents:
diff changeset
1147 {
kono
parents:
diff changeset
1148 const char *buf = pp_formatted_text (pp);
kono
parents:
diff changeset
1149 size_t len = strlen (buf);
kono
parents:
diff changeset
1150 tree ret = build_string (len + 1, buf);
kono
parents:
diff changeset
1151 TREE_TYPE (ret)
kono
parents:
diff changeset
1152 = build_array_type (TREE_TYPE (shadow_ptr_types[0]),
kono
parents:
diff changeset
1153 build_index_type (size_int (len)));
kono
parents:
diff changeset
1154 TREE_READONLY (ret) = 1;
kono
parents:
diff changeset
1155 TREE_STATIC (ret) = 1;
kono
parents:
diff changeset
1156 return build1 (ADDR_EXPR, shadow_ptr_types[0], ret);
kono
parents:
diff changeset
1157 }
kono
parents:
diff changeset
1158
kono
parents:
diff changeset
1159 /* Return a CONST_INT representing 4 subsequent shadow memory bytes. */
kono
parents:
diff changeset
1160
kono
parents:
diff changeset
1161 static rtx
kono
parents:
diff changeset
1162 asan_shadow_cst (unsigned char shadow_bytes[4])
kono
parents:
diff changeset
1163 {
kono
parents:
diff changeset
1164 int i;
kono
parents:
diff changeset
1165 unsigned HOST_WIDE_INT val = 0;
kono
parents:
diff changeset
1166 gcc_assert (WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN);
kono
parents:
diff changeset
1167 for (i = 0; i < 4; i++)
kono
parents:
diff changeset
1168 val |= (unsigned HOST_WIDE_INT) shadow_bytes[BYTES_BIG_ENDIAN ? 3 - i : i]
kono
parents:
diff changeset
1169 << (BITS_PER_UNIT * i);
kono
parents:
diff changeset
1170 return gen_int_mode (val, SImode);
kono
parents:
diff changeset
1171 }
kono
parents:
diff changeset
1172
kono
parents:
diff changeset
1173 /* Clear shadow memory at SHADOW_MEM, LEN bytes. Can't call a library call here
kono
parents:
diff changeset
1174 though. */
kono
parents:
diff changeset
1175
kono
parents:
diff changeset
1176 static void
kono
parents:
diff changeset
1177 asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len)
kono
parents:
diff changeset
1178 {
kono
parents:
diff changeset
1179 rtx_insn *insn, *insns, *jump;
kono
parents:
diff changeset
1180 rtx_code_label *top_label;
kono
parents:
diff changeset
1181 rtx end, addr, tmp;
kono
parents:
diff changeset
1182
kono
parents:
diff changeset
1183 start_sequence ();
kono
parents:
diff changeset
1184 clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL);
kono
parents:
diff changeset
1185 insns = get_insns ();
kono
parents:
diff changeset
1186 end_sequence ();
kono
parents:
diff changeset
1187 for (insn = insns; insn; insn = NEXT_INSN (insn))
kono
parents:
diff changeset
1188 if (CALL_P (insn))
kono
parents:
diff changeset
1189 break;
kono
parents:
diff changeset
1190 if (insn == NULL_RTX)
kono
parents:
diff changeset
1191 {
kono
parents:
diff changeset
1192 emit_insn (insns);
kono
parents:
diff changeset
1193 return;
kono
parents:
diff changeset
1194 }
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 gcc_assert ((len & 3) == 0);
kono
parents:
diff changeset
1197 top_label = gen_label_rtx ();
kono
parents:
diff changeset
1198 addr = copy_to_mode_reg (Pmode, XEXP (shadow_mem, 0));
kono
parents:
diff changeset
1199 shadow_mem = adjust_automodify_address (shadow_mem, SImode, addr, 0);
kono
parents:
diff changeset
1200 end = force_reg (Pmode, plus_constant (Pmode, addr, len));
kono
parents:
diff changeset
1201 emit_label (top_label);
kono
parents:
diff changeset
1202
kono
parents:
diff changeset
1203 emit_move_insn (shadow_mem, const0_rtx);
kono
parents:
diff changeset
1204 tmp = expand_simple_binop (Pmode, PLUS, addr, gen_int_mode (4, Pmode), addr,
kono
parents:
diff changeset
1205 true, OPTAB_LIB_WIDEN);
kono
parents:
diff changeset
1206 if (tmp != addr)
kono
parents:
diff changeset
1207 emit_move_insn (addr, tmp);
kono
parents:
diff changeset
1208 emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label);
kono
parents:
diff changeset
1209 jump = get_last_insn ();
kono
parents:
diff changeset
1210 gcc_assert (JUMP_P (jump));
kono
parents:
diff changeset
1211 add_reg_br_prob_note (jump,
kono
parents:
diff changeset
1212 profile_probability::guessed_always ()
kono
parents:
diff changeset
1213 .apply_scale (80, 100));
kono
parents:
diff changeset
1214 }
kono
parents:
diff changeset
1215
kono
parents:
diff changeset
1216 void
kono
parents:
diff changeset
1217 asan_function_start (void)
kono
parents:
diff changeset
1218 {
kono
parents:
diff changeset
1219 section *fnsec = function_section (current_function_decl);
kono
parents:
diff changeset
1220 switch_to_section (fnsec);
kono
parents:
diff changeset
1221 ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LASANPC",
kono
parents:
diff changeset
1222 current_function_funcdef_no);
kono
parents:
diff changeset
1223 }
kono
parents:
diff changeset
1224
kono
parents:
diff changeset
1225 /* Return number of shadow bytes that are occupied by a local variable
kono
parents:
diff changeset
1226 of SIZE bytes. */
kono
parents:
diff changeset
1227
kono
parents:
diff changeset
1228 static unsigned HOST_WIDE_INT
kono
parents:
diff changeset
1229 shadow_mem_size (unsigned HOST_WIDE_INT size)
kono
parents:
diff changeset
1230 {
kono
parents:
diff changeset
1231 return ROUND_UP (size, ASAN_SHADOW_GRANULARITY) / ASAN_SHADOW_GRANULARITY;
kono
parents:
diff changeset
1232 }
kono
parents:
diff changeset
1233
kono
parents:
diff changeset
1234 /* Insert code to protect stack vars. The prologue sequence should be emitted
kono
parents:
diff changeset
1235 directly, epilogue sequence returned. BASE is the register holding the
kono
parents:
diff changeset
1236 stack base, against which OFFSETS array offsets are relative to, OFFSETS
kono
parents:
diff changeset
1237 array contains pairs of offsets in reverse order, always the end offset
kono
parents:
diff changeset
1238 of some gap that needs protection followed by starting offset,
kono
parents:
diff changeset
1239 and DECLS is an array of representative decls for each var partition.
kono
parents:
diff changeset
1240 LENGTH is the length of the OFFSETS array, DECLS array is LENGTH / 2 - 1
kono
parents:
diff changeset
1241 elements long (OFFSETS include gap before the first variable as well
kono
parents:
diff changeset
1242 as gaps after each stack variable). PBASE is, if non-NULL, some pseudo
kono
parents:
diff changeset
1243 register which stack vars DECL_RTLs are based on. Either BASE should be
kono
parents:
diff changeset
1244 assigned to PBASE, when not doing use after return protection, or
kono
parents:
diff changeset
1245 corresponding address based on __asan_stack_malloc* return value. */
kono
parents:
diff changeset
1246
kono
parents:
diff changeset
1247 rtx_insn *
kono
parents:
diff changeset
1248 asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
kono
parents:
diff changeset
1249 HOST_WIDE_INT *offsets, tree *decls, int length)
kono
parents:
diff changeset
1250 {
kono
parents:
diff changeset
1251 rtx shadow_base, shadow_mem, ret, mem, orig_base;
kono
parents:
diff changeset
1252 rtx_code_label *lab;
kono
parents:
diff changeset
1253 rtx_insn *insns;
kono
parents:
diff changeset
1254 char buf[32];
kono
parents:
diff changeset
1255 unsigned char shadow_bytes[4];
kono
parents:
diff changeset
1256 HOST_WIDE_INT base_offset = offsets[length - 1];
kono
parents:
diff changeset
1257 HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
kono
parents:
diff changeset
1258 HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
kono
parents:
diff changeset
1259 HOST_WIDE_INT last_offset, last_size;
kono
parents:
diff changeset
1260 int l;
kono
parents:
diff changeset
1261 unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
kono
parents:
diff changeset
1262 tree str_cst, decl, id;
kono
parents:
diff changeset
1263 int use_after_return_class = -1;
kono
parents:
diff changeset
1264
kono
parents:
diff changeset
1265 if (shadow_ptr_types[0] == NULL_TREE)
kono
parents:
diff changeset
1266 asan_init_shadow_ptr_types ();
kono
parents:
diff changeset
1267
kono
parents:
diff changeset
1268 /* First of all, prepare the description string. */
kono
parents:
diff changeset
1269 pretty_printer asan_pp;
kono
parents:
diff changeset
1270
kono
parents:
diff changeset
1271 pp_decimal_int (&asan_pp, length / 2 - 1);
kono
parents:
diff changeset
1272 pp_space (&asan_pp);
kono
parents:
diff changeset
1273 for (l = length - 2; l; l -= 2)
kono
parents:
diff changeset
1274 {
kono
parents:
diff changeset
1275 tree decl = decls[l / 2 - 1];
kono
parents:
diff changeset
1276 pp_wide_integer (&asan_pp, offsets[l] - base_offset);
kono
parents:
diff changeset
1277 pp_space (&asan_pp);
kono
parents:
diff changeset
1278 pp_wide_integer (&asan_pp, offsets[l - 1] - offsets[l]);
kono
parents:
diff changeset
1279 pp_space (&asan_pp);
kono
parents:
diff changeset
1280 if (DECL_P (decl) && DECL_NAME (decl))
kono
parents:
diff changeset
1281 {
kono
parents:
diff changeset
1282 pp_decimal_int (&asan_pp, IDENTIFIER_LENGTH (DECL_NAME (decl)));
kono
parents:
diff changeset
1283 pp_space (&asan_pp);
kono
parents:
diff changeset
1284 pp_tree_identifier (&asan_pp, DECL_NAME (decl));
kono
parents:
diff changeset
1285 }
kono
parents:
diff changeset
1286 else
kono
parents:
diff changeset
1287 pp_string (&asan_pp, "9 <unknown>");
kono
parents:
diff changeset
1288 pp_space (&asan_pp);
kono
parents:
diff changeset
1289 }
kono
parents:
diff changeset
1290 str_cst = asan_pp_string (&asan_pp);
kono
parents:
diff changeset
1291
kono
parents:
diff changeset
1292 /* Emit the prologue sequence. */
kono
parents:
diff changeset
1293 if (asan_frame_size > 32 && asan_frame_size <= 65536 && pbase
kono
parents:
diff changeset
1294 && ASAN_USE_AFTER_RETURN)
kono
parents:
diff changeset
1295 {
kono
parents:
diff changeset
1296 use_after_return_class = floor_log2 (asan_frame_size - 1) - 5;
kono
parents:
diff changeset
1297 /* __asan_stack_malloc_N guarantees alignment
kono
parents:
diff changeset
1298 N < 6 ? (64 << N) : 4096 bytes. */
kono
parents:
diff changeset
1299 if (alignb > (use_after_return_class < 6
kono
parents:
diff changeset
1300 ? (64U << use_after_return_class) : 4096U))
kono
parents:
diff changeset
1301 use_after_return_class = -1;
kono
parents:
diff changeset
1302 else if (alignb > ASAN_RED_ZONE_SIZE && (asan_frame_size & (alignb - 1)))
kono
parents:
diff changeset
1303 base_align_bias = ((asan_frame_size + alignb - 1)
kono
parents:
diff changeset
1304 & ~(alignb - HOST_WIDE_INT_1)) - asan_frame_size;
kono
parents:
diff changeset
1305 }
kono
parents:
diff changeset
1306 /* Align base if target is STRICT_ALIGNMENT. */
kono
parents:
diff changeset
1307 if (STRICT_ALIGNMENT)
kono
parents:
diff changeset
1308 base = expand_binop (Pmode, and_optab, base,
kono
parents:
diff changeset
1309 gen_int_mode (-((GET_MODE_ALIGNMENT (SImode)
kono
parents:
diff changeset
1310 << ASAN_SHADOW_SHIFT)
kono
parents:
diff changeset
1311 / BITS_PER_UNIT), Pmode), NULL_RTX,
kono
parents:
diff changeset
1312 1, OPTAB_DIRECT);
kono
parents:
diff changeset
1313
kono
parents:
diff changeset
1314 if (use_after_return_class == -1 && pbase)
kono
parents:
diff changeset
1315 emit_move_insn (pbase, base);
kono
parents:
diff changeset
1316
kono
parents:
diff changeset
1317 base = expand_binop (Pmode, add_optab, base,
kono
parents:
diff changeset
1318 gen_int_mode (base_offset - base_align_bias, Pmode),
kono
parents:
diff changeset
1319 NULL_RTX, 1, OPTAB_DIRECT);
kono
parents:
diff changeset
1320 orig_base = NULL_RTX;
kono
parents:
diff changeset
1321 if (use_after_return_class != -1)
kono
parents:
diff changeset
1322 {
kono
parents:
diff changeset
1323 if (asan_detect_stack_use_after_return == NULL_TREE)
kono
parents:
diff changeset
1324 {
kono
parents:
diff changeset
1325 id = get_identifier ("__asan_option_detect_stack_use_after_return");
kono
parents:
diff changeset
1326 decl = build_decl (BUILTINS_LOCATION, VAR_DECL, id,
kono
parents:
diff changeset
1327 integer_type_node);
kono
parents:
diff changeset
1328 SET_DECL_ASSEMBLER_NAME (decl, id);
kono
parents:
diff changeset
1329 TREE_ADDRESSABLE (decl) = 1;
kono
parents:
diff changeset
1330 DECL_ARTIFICIAL (decl) = 1;
kono
parents:
diff changeset
1331 DECL_IGNORED_P (decl) = 1;
kono
parents:
diff changeset
1332 DECL_EXTERNAL (decl) = 1;
kono
parents:
diff changeset
1333 TREE_STATIC (decl) = 1;
kono
parents:
diff changeset
1334 TREE_PUBLIC (decl) = 1;
kono
parents:
diff changeset
1335 TREE_USED (decl) = 1;
kono
parents:
diff changeset
1336 asan_detect_stack_use_after_return = decl;
kono
parents:
diff changeset
1337 }
kono
parents:
diff changeset
1338 orig_base = gen_reg_rtx (Pmode);
kono
parents:
diff changeset
1339 emit_move_insn (orig_base, base);
kono
parents:
diff changeset
1340 ret = expand_normal (asan_detect_stack_use_after_return);
kono
parents:
diff changeset
1341 lab = gen_label_rtx ();
kono
parents:
diff changeset
1342 emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
kono
parents:
diff changeset
1343 VOIDmode, 0, lab,
kono
parents:
diff changeset
1344 profile_probability::very_likely ());
kono
parents:
diff changeset
1345 snprintf (buf, sizeof buf, "__asan_stack_malloc_%d",
kono
parents:
diff changeset
1346 use_after_return_class);
kono
parents:
diff changeset
1347 ret = init_one_libfunc (buf);
kono
parents:
diff changeset
1348 ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
kono
parents:
diff changeset
1349 GEN_INT (asan_frame_size
kono
parents:
diff changeset
1350 + base_align_bias),
kono
parents:
diff changeset
1351 TYPE_MODE (pointer_sized_int_node));
kono
parents:
diff changeset
1352 /* __asan_stack_malloc_[n] returns a pointer to fake stack if succeeded
kono
parents:
diff changeset
1353 and NULL otherwise. Check RET value is NULL here and jump over the
kono
parents:
diff changeset
1354 BASE reassignment in this case. Otherwise, reassign BASE to RET. */
kono
parents:
diff changeset
1355 emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
kono
parents:
diff changeset
1356 VOIDmode, 0, lab,
kono
parents:
diff changeset
1357 profile_probability:: very_unlikely ());
kono
parents:
diff changeset
1358 ret = convert_memory_address (Pmode, ret);
kono
parents:
diff changeset
1359 emit_move_insn (base, ret);
kono
parents:
diff changeset
1360 emit_label (lab);
kono
parents:
diff changeset
1361 emit_move_insn (pbase, expand_binop (Pmode, add_optab, base,
kono
parents:
diff changeset
1362 gen_int_mode (base_align_bias
kono
parents:
diff changeset
1363 - base_offset, Pmode),
kono
parents:
diff changeset
1364 NULL_RTX, 1, OPTAB_DIRECT));
kono
parents:
diff changeset
1365 }
kono
parents:
diff changeset
1366 mem = gen_rtx_MEM (ptr_mode, base);
kono
parents:
diff changeset
1367 mem = adjust_address (mem, VOIDmode, base_align_bias);
kono
parents:
diff changeset
1368 emit_move_insn (mem, gen_int_mode (ASAN_STACK_FRAME_MAGIC, ptr_mode));
kono
parents:
diff changeset
1369 mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
kono
parents:
diff changeset
1370 emit_move_insn (mem, expand_normal (str_cst));
kono
parents:
diff changeset
1371 mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
kono
parents:
diff changeset
1372 ASM_GENERATE_INTERNAL_LABEL (buf, "LASANPC", current_function_funcdef_no);
kono
parents:
diff changeset
1373 id = get_identifier (buf);
kono
parents:
diff changeset
1374 decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
kono
parents:
diff changeset
1375 VAR_DECL, id, char_type_node);
kono
parents:
diff changeset
1376 SET_DECL_ASSEMBLER_NAME (decl, id);
kono
parents:
diff changeset
1377 TREE_ADDRESSABLE (decl) = 1;
kono
parents:
diff changeset
1378 TREE_READONLY (decl) = 1;
kono
parents:
diff changeset
1379 DECL_ARTIFICIAL (decl) = 1;
kono
parents:
diff changeset
1380 DECL_IGNORED_P (decl) = 1;
kono
parents:
diff changeset
1381 TREE_STATIC (decl) = 1;
kono
parents:
diff changeset
1382 TREE_PUBLIC (decl) = 0;
kono
parents:
diff changeset
1383 TREE_USED (decl) = 1;
kono
parents:
diff changeset
1384 DECL_INITIAL (decl) = decl;
kono
parents:
diff changeset
1385 TREE_ASM_WRITTEN (decl) = 1;
kono
parents:
diff changeset
1386 TREE_ASM_WRITTEN (id) = 1;
kono
parents:
diff changeset
1387 emit_move_insn (mem, expand_normal (build_fold_addr_expr (decl)));
kono
parents:
diff changeset
1388 shadow_base = expand_binop (Pmode, lshr_optab, base,
kono
parents:
diff changeset
1389 GEN_INT (ASAN_SHADOW_SHIFT),
kono
parents:
diff changeset
1390 NULL_RTX, 1, OPTAB_DIRECT);
kono
parents:
diff changeset
1391 shadow_base
kono
parents:
diff changeset
1392 = plus_constant (Pmode, shadow_base,
kono
parents:
diff changeset
1393 asan_shadow_offset ()
kono
parents:
diff changeset
1394 + (base_align_bias >> ASAN_SHADOW_SHIFT));
kono
parents:
diff changeset
1395 gcc_assert (asan_shadow_set != -1
kono
parents:
diff changeset
1396 && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
kono
parents:
diff changeset
1397 shadow_mem = gen_rtx_MEM (SImode, shadow_base);
kono
parents:
diff changeset
1398 set_mem_alias_set (shadow_mem, asan_shadow_set);
kono
parents:
diff changeset
1399 if (STRICT_ALIGNMENT)
kono
parents:
diff changeset
1400 set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
kono
parents:
diff changeset
1401 prev_offset = base_offset;
kono
parents:
diff changeset
1402 for (l = length; l; l -= 2)
kono
parents:
diff changeset
1403 {
kono
parents:
diff changeset
1404 if (l == 2)
kono
parents:
diff changeset
1405 cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT;
kono
parents:
diff changeset
1406 offset = offsets[l - 1];
kono
parents:
diff changeset
1407 if ((offset - base_offset) & (ASAN_RED_ZONE_SIZE - 1))
kono
parents:
diff changeset
1408 {
kono
parents:
diff changeset
1409 int i;
kono
parents:
diff changeset
1410 HOST_WIDE_INT aoff
kono
parents:
diff changeset
1411 = base_offset + ((offset - base_offset)
kono
parents:
diff changeset
1412 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
kono
parents:
diff changeset
1413 shadow_mem = adjust_address (shadow_mem, VOIDmode,
kono
parents:
diff changeset
1414 (aoff - prev_offset)
kono
parents:
diff changeset
1415 >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1416 prev_offset = aoff;
kono
parents:
diff changeset
1417 for (i = 0; i < 4; i++, aoff += ASAN_SHADOW_GRANULARITY)
kono
parents:
diff changeset
1418 if (aoff < offset)
kono
parents:
diff changeset
1419 {
kono
parents:
diff changeset
1420 if (aoff < offset - (HOST_WIDE_INT)ASAN_SHADOW_GRANULARITY + 1)
kono
parents:
diff changeset
1421 shadow_bytes[i] = 0;
kono
parents:
diff changeset
1422 else
kono
parents:
diff changeset
1423 shadow_bytes[i] = offset - aoff;
kono
parents:
diff changeset
1424 }
kono
parents:
diff changeset
1425 else
kono
parents:
diff changeset
1426 shadow_bytes[i] = ASAN_STACK_MAGIC_MIDDLE;
kono
parents:
diff changeset
1427 emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
kono
parents:
diff changeset
1428 offset = aoff;
kono
parents:
diff changeset
1429 }
kono
parents:
diff changeset
1430 while (offset <= offsets[l - 2] - ASAN_RED_ZONE_SIZE)
kono
parents:
diff changeset
1431 {
kono
parents:
diff changeset
1432 shadow_mem = adjust_address (shadow_mem, VOIDmode,
kono
parents:
diff changeset
1433 (offset - prev_offset)
kono
parents:
diff changeset
1434 >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1435 prev_offset = offset;
kono
parents:
diff changeset
1436 memset (shadow_bytes, cur_shadow_byte, 4);
kono
parents:
diff changeset
1437 emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
kono
parents:
diff changeset
1438 offset += ASAN_RED_ZONE_SIZE;
kono
parents:
diff changeset
1439 }
kono
parents:
diff changeset
1440 cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE;
kono
parents:
diff changeset
1441 }
kono
parents:
diff changeset
1442 do_pending_stack_adjust ();
kono
parents:
diff changeset
1443
kono
parents:
diff changeset
1444 /* Construct epilogue sequence. */
kono
parents:
diff changeset
1445 start_sequence ();
kono
parents:
diff changeset
1446
kono
parents:
diff changeset
1447 lab = NULL;
kono
parents:
diff changeset
1448 if (use_after_return_class != -1)
kono
parents:
diff changeset
1449 {
kono
parents:
diff changeset
1450 rtx_code_label *lab2 = gen_label_rtx ();
kono
parents:
diff changeset
1451 char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
kono
parents:
diff changeset
1452 emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
kono
parents:
diff changeset
1453 VOIDmode, 0, lab2,
kono
parents:
diff changeset
1454 profile_probability::very_likely ());
kono
parents:
diff changeset
1455 shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
kono
parents:
diff changeset
1456 set_mem_alias_set (shadow_mem, asan_shadow_set);
kono
parents:
diff changeset
1457 mem = gen_rtx_MEM (ptr_mode, base);
kono
parents:
diff changeset
1458 mem = adjust_address (mem, VOIDmode, base_align_bias);
kono
parents:
diff changeset
1459 emit_move_insn (mem, gen_int_mode (ASAN_STACK_RETIRED_MAGIC, ptr_mode));
kono
parents:
diff changeset
1460 unsigned HOST_WIDE_INT sz = asan_frame_size >> ASAN_SHADOW_SHIFT;
kono
parents:
diff changeset
1461 if (use_after_return_class < 5
kono
parents:
diff changeset
1462 && can_store_by_pieces (sz, builtin_memset_read_str, &c,
kono
parents:
diff changeset
1463 BITS_PER_UNIT, true))
kono
parents:
diff changeset
1464 store_by_pieces (shadow_mem, sz, builtin_memset_read_str, &c,
kono
parents:
diff changeset
1465 BITS_PER_UNIT, true, 0);
kono
parents:
diff changeset
1466 else if (use_after_return_class >= 5
kono
parents:
diff changeset
1467 || !set_storage_via_setmem (shadow_mem,
kono
parents:
diff changeset
1468 GEN_INT (sz),
kono
parents:
diff changeset
1469 gen_int_mode (c, QImode),
kono
parents:
diff changeset
1470 BITS_PER_UNIT, BITS_PER_UNIT,
kono
parents:
diff changeset
1471 -1, sz, sz, sz))
kono
parents:
diff changeset
1472 {
kono
parents:
diff changeset
1473 snprintf (buf, sizeof buf, "__asan_stack_free_%d",
kono
parents:
diff changeset
1474 use_after_return_class);
kono
parents:
diff changeset
1475 ret = init_one_libfunc (buf);
kono
parents:
diff changeset
1476 rtx addr = convert_memory_address (ptr_mode, base);
kono
parents:
diff changeset
1477 rtx orig_addr = convert_memory_address (ptr_mode, orig_base);
kono
parents:
diff changeset
1478 emit_library_call (ret, LCT_NORMAL, ptr_mode, addr, ptr_mode,
kono
parents:
diff changeset
1479 GEN_INT (asan_frame_size + base_align_bias),
kono
parents:
diff changeset
1480 TYPE_MODE (pointer_sized_int_node),
kono
parents:
diff changeset
1481 orig_addr, ptr_mode);
kono
parents:
diff changeset
1482 }
kono
parents:
diff changeset
1483 lab = gen_label_rtx ();
kono
parents:
diff changeset
1484 emit_jump (lab);
kono
parents:
diff changeset
1485 emit_label (lab2);
kono
parents:
diff changeset
1486 }
kono
parents:
diff changeset
1487
kono
parents:
diff changeset
1488 shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
kono
parents:
diff changeset
1489 set_mem_alias_set (shadow_mem, asan_shadow_set);
kono
parents:
diff changeset
1490
kono
parents:
diff changeset
1491 if (STRICT_ALIGNMENT)
kono
parents:
diff changeset
1492 set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
kono
parents:
diff changeset
1493
kono
parents:
diff changeset
1494 prev_offset = base_offset;
kono
parents:
diff changeset
1495 last_offset = base_offset;
kono
parents:
diff changeset
1496 last_size = 0;
kono
parents:
diff changeset
1497 for (l = length; l; l -= 2)
kono
parents:
diff changeset
1498 {
kono
parents:
diff changeset
1499 offset = base_offset + ((offsets[l - 1] - base_offset)
kono
parents:
diff changeset
1500 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
kono
parents:
diff changeset
1501 if (last_offset + last_size != offset)
kono
parents:
diff changeset
1502 {
kono
parents:
diff changeset
1503 shadow_mem = adjust_address (shadow_mem, VOIDmode,
kono
parents:
diff changeset
1504 (last_offset - prev_offset)
kono
parents:
diff changeset
1505 >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1506 prev_offset = last_offset;
kono
parents:
diff changeset
1507 asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1508 last_offset = offset;
kono
parents:
diff changeset
1509 last_size = 0;
kono
parents:
diff changeset
1510 }
kono
parents:
diff changeset
1511 last_size += base_offset + ((offsets[l - 2] - base_offset)
kono
parents:
diff changeset
1512 & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
kono
parents:
diff changeset
1513 - offset;
kono
parents:
diff changeset
1514
kono
parents:
diff changeset
1515 /* Unpoison shadow memory that corresponds to a variable that is
kono
parents:
diff changeset
1516 is subject of use-after-return sanitization. */
kono
parents:
diff changeset
1517 if (l > 2)
kono
parents:
diff changeset
1518 {
kono
parents:
diff changeset
1519 decl = decls[l / 2 - 2];
kono
parents:
diff changeset
1520 if (asan_handled_variables != NULL
kono
parents:
diff changeset
1521 && asan_handled_variables->contains (decl))
kono
parents:
diff changeset
1522 {
kono
parents:
diff changeset
1523 HOST_WIDE_INT size = offsets[l - 3] - offsets[l - 2];
kono
parents:
diff changeset
1524 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
1525 {
kono
parents:
diff changeset
1526 const char *n = (DECL_NAME (decl)
kono
parents:
diff changeset
1527 ? IDENTIFIER_POINTER (DECL_NAME (decl))
kono
parents:
diff changeset
1528 : "<unknown>");
kono
parents:
diff changeset
1529 fprintf (dump_file, "Unpoisoning shadow stack for variable: "
kono
parents:
diff changeset
1530 "%s (%" PRId64 " B)\n", n, size);
kono
parents:
diff changeset
1531 }
kono
parents:
diff changeset
1532
kono
parents:
diff changeset
1533 last_size += size & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1);
kono
parents:
diff changeset
1534 }
kono
parents:
diff changeset
1535 }
kono
parents:
diff changeset
1536 }
kono
parents:
diff changeset
1537 if (last_size)
kono
parents:
diff changeset
1538 {
kono
parents:
diff changeset
1539 shadow_mem = adjust_address (shadow_mem, VOIDmode,
kono
parents:
diff changeset
1540 (last_offset - prev_offset)
kono
parents:
diff changeset
1541 >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1542 asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1543 }
kono
parents:
diff changeset
1544
kono
parents:
diff changeset
1545 /* Clean-up set with instrumented stack variables. */
kono
parents:
diff changeset
1546 delete asan_handled_variables;
kono
parents:
diff changeset
1547 asan_handled_variables = NULL;
kono
parents:
diff changeset
1548 delete asan_used_labels;
kono
parents:
diff changeset
1549 asan_used_labels = NULL;
kono
parents:
diff changeset
1550
kono
parents:
diff changeset
1551 do_pending_stack_adjust ();
kono
parents:
diff changeset
1552 if (lab)
kono
parents:
diff changeset
1553 emit_label (lab);
kono
parents:
diff changeset
1554
kono
parents:
diff changeset
1555 insns = get_insns ();
kono
parents:
diff changeset
1556 end_sequence ();
kono
parents:
diff changeset
1557 return insns;
kono
parents:
diff changeset
1558 }
kono
parents:
diff changeset
1559
kono
parents:
diff changeset
1560 /* Emit __asan_allocas_unpoison (top, bot) call. The BASE parameter corresponds
kono
parents:
diff changeset
1561 to BOT argument, for TOP virtual_stack_dynamic_rtx is used. NEW_SEQUENCE
kono
parents:
diff changeset
1562 indicates whether we're emitting new instructions sequence or not. */
kono
parents:
diff changeset
1563
kono
parents:
diff changeset
1564 rtx_insn *
kono
parents:
diff changeset
1565 asan_emit_allocas_unpoison (rtx top, rtx bot, rtx_insn *before)
kono
parents:
diff changeset
1566 {
kono
parents:
diff changeset
1567 if (before)
kono
parents:
diff changeset
1568 push_to_sequence (before);
kono
parents:
diff changeset
1569 else
kono
parents:
diff changeset
1570 start_sequence ();
kono
parents:
diff changeset
1571 rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
kono
parents:
diff changeset
1572 top = convert_memory_address (ptr_mode, top);
kono
parents:
diff changeset
1573 bot = convert_memory_address (ptr_mode, bot);
kono
parents:
diff changeset
1574 ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
kono
parents:
diff changeset
1575 top, ptr_mode, bot, ptr_mode);
kono
parents:
diff changeset
1576
kono
parents:
diff changeset
1577 do_pending_stack_adjust ();
kono
parents:
diff changeset
1578 rtx_insn *insns = get_insns ();
kono
parents:
diff changeset
1579 end_sequence ();
kono
parents:
diff changeset
1580 return insns;
kono
parents:
diff changeset
1581 }
kono
parents:
diff changeset
1582
kono
parents:
diff changeset
1583 /* Return true if DECL, a global var, might be overridden and needs
kono
parents:
diff changeset
1584 therefore a local alias. */
kono
parents:
diff changeset
1585
kono
parents:
diff changeset
1586 static bool
kono
parents:
diff changeset
1587 asan_needs_local_alias (tree decl)
kono
parents:
diff changeset
1588 {
kono
parents:
diff changeset
1589 return DECL_WEAK (decl) || !targetm.binds_local_p (decl);
kono
parents:
diff changeset
1590 }
kono
parents:
diff changeset
1591
kono
parents:
diff changeset
1592 /* Return true if DECL, a global var, is an artificial ODR indicator symbol
kono
parents:
diff changeset
1593 therefore doesn't need protection. */
kono
parents:
diff changeset
1594
kono
parents:
diff changeset
1595 static bool
kono
parents:
diff changeset
1596 is_odr_indicator (tree decl)
kono
parents:
diff changeset
1597 {
kono
parents:
diff changeset
1598 return (DECL_ARTIFICIAL (decl)
kono
parents:
diff changeset
1599 && lookup_attribute ("asan odr indicator", DECL_ATTRIBUTES (decl)));
kono
parents:
diff changeset
1600 }
kono
parents:
diff changeset
1601
kono
parents:
diff changeset
1602 /* Return true if DECL is a VAR_DECL that should be protected
kono
parents:
diff changeset
1603 by Address Sanitizer, by appending a red zone with protected
kono
parents:
diff changeset
1604 shadow memory after it and aligning it to at least
kono
parents:
diff changeset
1605 ASAN_RED_ZONE_SIZE bytes. */
kono
parents:
diff changeset
1606
kono
parents:
diff changeset
1607 bool
kono
parents:
diff changeset
1608 asan_protect_global (tree decl)
kono
parents:
diff changeset
1609 {
kono
parents:
diff changeset
1610 if (!ASAN_GLOBALS)
kono
parents:
diff changeset
1611 return false;
kono
parents:
diff changeset
1612
kono
parents:
diff changeset
1613 rtx rtl, symbol;
kono
parents:
diff changeset
1614
kono
parents:
diff changeset
1615 if (TREE_CODE (decl) == STRING_CST)
kono
parents:
diff changeset
1616 {
kono
parents:
diff changeset
1617 /* Instrument all STRING_CSTs except those created
kono
parents:
diff changeset
1618 by asan_pp_string here. */
kono
parents:
diff changeset
1619 if (shadow_ptr_types[0] != NULL_TREE
kono
parents:
diff changeset
1620 && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
kono
parents:
diff changeset
1621 && TREE_TYPE (TREE_TYPE (decl)) == TREE_TYPE (shadow_ptr_types[0]))
kono
parents:
diff changeset
1622 return false;
kono
parents:
diff changeset
1623 return true;
kono
parents:
diff changeset
1624 }
kono
parents:
diff changeset
1625 if (!VAR_P (decl)
kono
parents:
diff changeset
1626 /* TLS vars aren't statically protectable. */
kono
parents:
diff changeset
1627 || DECL_THREAD_LOCAL_P (decl)
kono
parents:
diff changeset
1628 /* Externs will be protected elsewhere. */
kono
parents:
diff changeset
1629 || DECL_EXTERNAL (decl)
kono
parents:
diff changeset
1630 || !DECL_RTL_SET_P (decl)
kono
parents:
diff changeset
1631 /* Comdat vars pose an ABI problem, we can't know if
kono
parents:
diff changeset
1632 the var that is selected by the linker will have
kono
parents:
diff changeset
1633 padding or not. */
kono
parents:
diff changeset
1634 || DECL_ONE_ONLY (decl)
kono
parents:
diff changeset
1635 /* Similarly for common vars. People can use -fno-common.
kono
parents:
diff changeset
1636 Note: Linux kernel is built with -fno-common, so we do instrument
kono
parents:
diff changeset
1637 globals there even if it is C. */
kono
parents:
diff changeset
1638 || (DECL_COMMON (decl) && TREE_PUBLIC (decl))
kono
parents:
diff changeset
1639 /* Don't protect if using user section, often vars placed
kono
parents:
diff changeset
1640 into user section from multiple TUs are then assumed
kono
parents:
diff changeset
1641 to be an array of such vars, putting padding in there
kono
parents:
diff changeset
1642 breaks this assumption. */
kono
parents:
diff changeset
1643 || (DECL_SECTION_NAME (decl) != NULL
kono
parents:
diff changeset
1644 && !symtab_node::get (decl)->implicit_section
kono
parents:
diff changeset
1645 && !section_sanitized_p (DECL_SECTION_NAME (decl)))
kono
parents:
diff changeset
1646 || DECL_SIZE (decl) == 0
kono
parents:
diff changeset
1647 || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
kono
parents:
diff changeset
1648 || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
kono
parents:
diff changeset
1649 || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE
kono
parents:
diff changeset
1650 || TREE_TYPE (decl) == ubsan_get_source_location_type ()
kono
parents:
diff changeset
1651 || is_odr_indicator (decl))
kono
parents:
diff changeset
1652 return false;
kono
parents:
diff changeset
1653
kono
parents:
diff changeset
1654 rtl = DECL_RTL (decl);
kono
parents:
diff changeset
1655 if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF)
kono
parents:
diff changeset
1656 return false;
kono
parents:
diff changeset
1657 symbol = XEXP (rtl, 0);
kono
parents:
diff changeset
1658
kono
parents:
diff changeset
1659 if (CONSTANT_POOL_ADDRESS_P (symbol)
kono
parents:
diff changeset
1660 || TREE_CONSTANT_POOL_ADDRESS_P (symbol))
kono
parents:
diff changeset
1661 return false;
kono
parents:
diff changeset
1662
kono
parents:
diff changeset
1663 if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
kono
parents:
diff changeset
1664 return false;
kono
parents:
diff changeset
1665
kono
parents:
diff changeset
1666 if (!TARGET_SUPPORTS_ALIASES && asan_needs_local_alias (decl))
kono
parents:
diff changeset
1667 return false;
kono
parents:
diff changeset
1668
kono
parents:
diff changeset
1669 return true;
kono
parents:
diff changeset
1670 }
kono
parents:
diff changeset
1671
kono
parents:
diff changeset
1672 /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16,_n}.
kono
parents:
diff changeset
1673 IS_STORE is either 1 (for a store) or 0 (for a load). */
kono
parents:
diff changeset
1674
kono
parents:
diff changeset
1675 static tree
kono
parents:
diff changeset
1676 report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
kono
parents:
diff changeset
1677 int *nargs)
kono
parents:
diff changeset
1678 {
kono
parents:
diff changeset
1679 static enum built_in_function report[2][2][6]
kono
parents:
diff changeset
1680 = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
kono
parents:
diff changeset
1681 BUILT_IN_ASAN_REPORT_LOAD4, BUILT_IN_ASAN_REPORT_LOAD8,
kono
parents:
diff changeset
1682 BUILT_IN_ASAN_REPORT_LOAD16, BUILT_IN_ASAN_REPORT_LOAD_N },
kono
parents:
diff changeset
1683 { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
kono
parents:
diff changeset
1684 BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
kono
parents:
diff changeset
1685 BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } },
kono
parents:
diff changeset
1686 { { BUILT_IN_ASAN_REPORT_LOAD1_NOABORT,
kono
parents:
diff changeset
1687 BUILT_IN_ASAN_REPORT_LOAD2_NOABORT,
kono
parents:
diff changeset
1688 BUILT_IN_ASAN_REPORT_LOAD4_NOABORT,
kono
parents:
diff changeset
1689 BUILT_IN_ASAN_REPORT_LOAD8_NOABORT,
kono
parents:
diff changeset
1690 BUILT_IN_ASAN_REPORT_LOAD16_NOABORT,
kono
parents:
diff changeset
1691 BUILT_IN_ASAN_REPORT_LOAD_N_NOABORT },
kono
parents:
diff changeset
1692 { BUILT_IN_ASAN_REPORT_STORE1_NOABORT,
kono
parents:
diff changeset
1693 BUILT_IN_ASAN_REPORT_STORE2_NOABORT,
kono
parents:
diff changeset
1694 BUILT_IN_ASAN_REPORT_STORE4_NOABORT,
kono
parents:
diff changeset
1695 BUILT_IN_ASAN_REPORT_STORE8_NOABORT,
kono
parents:
diff changeset
1696 BUILT_IN_ASAN_REPORT_STORE16_NOABORT,
kono
parents:
diff changeset
1697 BUILT_IN_ASAN_REPORT_STORE_N_NOABORT } } };
kono
parents:
diff changeset
1698 if (size_in_bytes == -1)
kono
parents:
diff changeset
1699 {
kono
parents:
diff changeset
1700 *nargs = 2;
kono
parents:
diff changeset
1701 return builtin_decl_implicit (report[recover_p][is_store][5]);
kono
parents:
diff changeset
1702 }
kono
parents:
diff changeset
1703 *nargs = 1;
kono
parents:
diff changeset
1704 int size_log2 = exact_log2 (size_in_bytes);
kono
parents:
diff changeset
1705 return builtin_decl_implicit (report[recover_p][is_store][size_log2]);
kono
parents:
diff changeset
1706 }
kono
parents:
diff changeset
1707
kono
parents:
diff changeset
1708 /* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
kono
parents:
diff changeset
1709 IS_STORE is either 1 (for a store) or 0 (for a load). */
kono
parents:
diff changeset
1710
kono
parents:
diff changeset
1711 static tree
kono
parents:
diff changeset
1712 check_func (bool is_store, bool recover_p, HOST_WIDE_INT size_in_bytes,
kono
parents:
diff changeset
1713 int *nargs)
kono
parents:
diff changeset
1714 {
kono
parents:
diff changeset
1715 static enum built_in_function check[2][2][6]
kono
parents:
diff changeset
1716 = { { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
kono
parents:
diff changeset
1717 BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
kono
parents:
diff changeset
1718 BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
kono
parents:
diff changeset
1719 { BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
kono
parents:
diff changeset
1720 BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
kono
parents:
diff changeset
1721 BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } },
kono
parents:
diff changeset
1722 { { BUILT_IN_ASAN_LOAD1_NOABORT,
kono
parents:
diff changeset
1723 BUILT_IN_ASAN_LOAD2_NOABORT,
kono
parents:
diff changeset
1724 BUILT_IN_ASAN_LOAD4_NOABORT,
kono
parents:
diff changeset
1725 BUILT_IN_ASAN_LOAD8_NOABORT,
kono
parents:
diff changeset
1726 BUILT_IN_ASAN_LOAD16_NOABORT,
kono
parents:
diff changeset
1727 BUILT_IN_ASAN_LOADN_NOABORT },
kono
parents:
diff changeset
1728 { BUILT_IN_ASAN_STORE1_NOABORT,
kono
parents:
diff changeset
1729 BUILT_IN_ASAN_STORE2_NOABORT,
kono
parents:
diff changeset
1730 BUILT_IN_ASAN_STORE4_NOABORT,
kono
parents:
diff changeset
1731 BUILT_IN_ASAN_STORE8_NOABORT,
kono
parents:
diff changeset
1732 BUILT_IN_ASAN_STORE16_NOABORT,
kono
parents:
diff changeset
1733 BUILT_IN_ASAN_STOREN_NOABORT } } };
kono
parents:
diff changeset
1734 if (size_in_bytes == -1)
kono
parents:
diff changeset
1735 {
kono
parents:
diff changeset
1736 *nargs = 2;
kono
parents:
diff changeset
1737 return builtin_decl_implicit (check[recover_p][is_store][5]);
kono
parents:
diff changeset
1738 }
kono
parents:
diff changeset
1739 *nargs = 1;
kono
parents:
diff changeset
1740 int size_log2 = exact_log2 (size_in_bytes);
kono
parents:
diff changeset
1741 return builtin_decl_implicit (check[recover_p][is_store][size_log2]);
kono
parents:
diff changeset
1742 }
kono
parents:
diff changeset
1743
kono
parents:
diff changeset
1744 /* Split the current basic block and create a condition statement
kono
parents:
diff changeset
1745 insertion point right before or after the statement pointed to by
kono
parents:
diff changeset
1746 ITER. Return an iterator to the point at which the caller might
kono
parents:
diff changeset
1747 safely insert the condition statement.
kono
parents:
diff changeset
1748
kono
parents:
diff changeset
1749 THEN_BLOCK must be set to the address of an uninitialized instance
kono
parents:
diff changeset
1750 of basic_block. The function will then set *THEN_BLOCK to the
kono
parents:
diff changeset
1751 'then block' of the condition statement to be inserted by the
kono
parents:
diff changeset
1752 caller.
kono
parents:
diff changeset
1753
kono
parents:
diff changeset
1754 If CREATE_THEN_FALLTHRU_EDGE is false, no edge will be created from
kono
parents:
diff changeset
1755 *THEN_BLOCK to *FALLTHROUGH_BLOCK.
kono
parents:
diff changeset
1756
kono
parents:
diff changeset
1757 Similarly, the function will set *FALLTRHOUGH_BLOCK to the 'else
kono
parents:
diff changeset
1758 block' of the condition statement to be inserted by the caller.
kono
parents:
diff changeset
1759
kono
parents:
diff changeset
1760 Note that *FALLTHROUGH_BLOCK is a new block that contains the
kono
parents:
diff changeset
1761 statements starting from *ITER, and *THEN_BLOCK is a new empty
kono
parents:
diff changeset
1762 block.
kono
parents:
diff changeset
1763
kono
parents:
diff changeset
1764 *ITER is adjusted to point to always point to the first statement
kono
parents:
diff changeset
1765 of the basic block * FALLTHROUGH_BLOCK. That statement is the
kono
parents:
diff changeset
1766 same as what ITER was pointing to prior to calling this function,
kono
parents:
diff changeset
1767 if BEFORE_P is true; otherwise, it is its following statement. */
kono
parents:
diff changeset
1768
kono
parents:
diff changeset
1769 gimple_stmt_iterator
kono
parents:
diff changeset
1770 create_cond_insert_point (gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1771 bool before_p,
kono
parents:
diff changeset
1772 bool then_more_likely_p,
kono
parents:
diff changeset
1773 bool create_then_fallthru_edge,
kono
parents:
diff changeset
1774 basic_block *then_block,
kono
parents:
diff changeset
1775 basic_block *fallthrough_block)
kono
parents:
diff changeset
1776 {
kono
parents:
diff changeset
1777 gimple_stmt_iterator gsi = *iter;
kono
parents:
diff changeset
1778
kono
parents:
diff changeset
1779 if (!gsi_end_p (gsi) && before_p)
kono
parents:
diff changeset
1780 gsi_prev (&gsi);
kono
parents:
diff changeset
1781
kono
parents:
diff changeset
1782 basic_block cur_bb = gsi_bb (*iter);
kono
parents:
diff changeset
1783
kono
parents:
diff changeset
1784 edge e = split_block (cur_bb, gsi_stmt (gsi));
kono
parents:
diff changeset
1785
kono
parents:
diff changeset
1786 /* Get a hold on the 'condition block', the 'then block' and the
kono
parents:
diff changeset
1787 'else block'. */
kono
parents:
diff changeset
1788 basic_block cond_bb = e->src;
kono
parents:
diff changeset
1789 basic_block fallthru_bb = e->dest;
kono
parents:
diff changeset
1790 basic_block then_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
1791 if (current_loops)
kono
parents:
diff changeset
1792 {
kono
parents:
diff changeset
1793 add_bb_to_loop (then_bb, cond_bb->loop_father);
kono
parents:
diff changeset
1794 loops_state_set (LOOPS_NEED_FIXUP);
kono
parents:
diff changeset
1795 }
kono
parents:
diff changeset
1796
kono
parents:
diff changeset
1797 /* Set up the newly created 'then block'. */
kono
parents:
diff changeset
1798 e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1799 profile_probability fallthrough_probability
kono
parents:
diff changeset
1800 = then_more_likely_p
kono
parents:
diff changeset
1801 ? profile_probability::very_unlikely ()
kono
parents:
diff changeset
1802 : profile_probability::very_likely ();
kono
parents:
diff changeset
1803 e->probability = fallthrough_probability.invert ();
kono
parents:
diff changeset
1804 if (create_then_fallthru_edge)
kono
parents:
diff changeset
1805 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
1806
kono
parents:
diff changeset
1807 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
1808 e = find_edge (cond_bb, fallthru_bb);
kono
parents:
diff changeset
1809 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
1810 e->probability = fallthrough_probability;
kono
parents:
diff changeset
1811
kono
parents:
diff changeset
1812 /* Update dominance info for the newly created then_bb; note that
kono
parents:
diff changeset
1813 fallthru_bb's dominance info has already been updated by
kono
parents:
diff changeset
1814 split_bock. */
kono
parents:
diff changeset
1815 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
1816 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
kono
parents:
diff changeset
1817
kono
parents:
diff changeset
1818 *then_block = then_bb;
kono
parents:
diff changeset
1819 *fallthrough_block = fallthru_bb;
kono
parents:
diff changeset
1820 *iter = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
1821
kono
parents:
diff changeset
1822 return gsi_last_bb (cond_bb);
kono
parents:
diff changeset
1823 }
kono
parents:
diff changeset
1824
kono
parents:
diff changeset
1825 /* Insert an if condition followed by a 'then block' right before the
kono
parents:
diff changeset
1826 statement pointed to by ITER. The fallthrough block -- which is the
kono
parents:
diff changeset
1827 else block of the condition as well as the destination of the
kono
parents:
diff changeset
1828 outcoming edge of the 'then block' -- starts with the statement
kono
parents:
diff changeset
1829 pointed to by ITER.
kono
parents:
diff changeset
1830
kono
parents:
diff changeset
1831 COND is the condition of the if.
kono
parents:
diff changeset
1832
kono
parents:
diff changeset
1833 If THEN_MORE_LIKELY_P is true, the probability of the edge to the
kono
parents:
diff changeset
1834 'then block' is higher than the probability of the edge to the
kono
parents:
diff changeset
1835 fallthrough block.
kono
parents:
diff changeset
1836
kono
parents:
diff changeset
1837 Upon completion of the function, *THEN_BB is set to the newly
kono
parents:
diff changeset
1838 inserted 'then block' and similarly, *FALLTHROUGH_BB is set to the
kono
parents:
diff changeset
1839 fallthrough block.
kono
parents:
diff changeset
1840
kono
parents:
diff changeset
1841 *ITER is adjusted to still point to the same statement it was
kono
parents:
diff changeset
1842 pointing to initially. */
kono
parents:
diff changeset
1843
kono
parents:
diff changeset
1844 static void
kono
parents:
diff changeset
1845 insert_if_then_before_iter (gcond *cond,
kono
parents:
diff changeset
1846 gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1847 bool then_more_likely_p,
kono
parents:
diff changeset
1848 basic_block *then_bb,
kono
parents:
diff changeset
1849 basic_block *fallthrough_bb)
kono
parents:
diff changeset
1850 {
kono
parents:
diff changeset
1851 gimple_stmt_iterator cond_insert_point =
kono
parents:
diff changeset
1852 create_cond_insert_point (iter,
kono
parents:
diff changeset
1853 /*before_p=*/true,
kono
parents:
diff changeset
1854 then_more_likely_p,
kono
parents:
diff changeset
1855 /*create_then_fallthru_edge=*/true,
kono
parents:
diff changeset
1856 then_bb,
kono
parents:
diff changeset
1857 fallthrough_bb);
kono
parents:
diff changeset
1858 gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT);
kono
parents:
diff changeset
1859 }
kono
parents:
diff changeset
1860
kono
parents:
diff changeset
1861 /* Build (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset ().
kono
parents:
diff changeset
1862 If RETURN_ADDRESS is set to true, return memory location instread
kono
parents:
diff changeset
1863 of a value in the shadow memory. */
kono
parents:
diff changeset
1864
kono
parents:
diff changeset
1865 static tree
kono
parents:
diff changeset
1866 build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
kono
parents:
diff changeset
1867 tree base_addr, tree shadow_ptr_type,
kono
parents:
diff changeset
1868 bool return_address = false)
kono
parents:
diff changeset
1869 {
kono
parents:
diff changeset
1870 tree t, uintptr_type = TREE_TYPE (base_addr);
kono
parents:
diff changeset
1871 tree shadow_type = TREE_TYPE (shadow_ptr_type);
kono
parents:
diff changeset
1872 gimple *g;
kono
parents:
diff changeset
1873
kono
parents:
diff changeset
1874 t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
kono
parents:
diff changeset
1875 g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
kono
parents:
diff changeset
1876 base_addr, t);
kono
parents:
diff changeset
1877 gimple_set_location (g, location);
kono
parents:
diff changeset
1878 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1879
kono
parents:
diff changeset
1880 t = build_int_cst (uintptr_type, asan_shadow_offset ());
kono
parents:
diff changeset
1881 g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
kono
parents:
diff changeset
1882 gimple_assign_lhs (g), t);
kono
parents:
diff changeset
1883 gimple_set_location (g, location);
kono
parents:
diff changeset
1884 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1885
kono
parents:
diff changeset
1886 g = gimple_build_assign (make_ssa_name (shadow_ptr_type), NOP_EXPR,
kono
parents:
diff changeset
1887 gimple_assign_lhs (g));
kono
parents:
diff changeset
1888 gimple_set_location (g, location);
kono
parents:
diff changeset
1889 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1890
kono
parents:
diff changeset
1891 if (!return_address)
kono
parents:
diff changeset
1892 {
kono
parents:
diff changeset
1893 t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
kono
parents:
diff changeset
1894 build_int_cst (shadow_ptr_type, 0));
kono
parents:
diff changeset
1895 g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
kono
parents:
diff changeset
1896 gimple_set_location (g, location);
kono
parents:
diff changeset
1897 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1898 }
kono
parents:
diff changeset
1899
kono
parents:
diff changeset
1900 return gimple_assign_lhs (g);
kono
parents:
diff changeset
1901 }
kono
parents:
diff changeset
1902
kono
parents:
diff changeset
1903 /* BASE can already be an SSA_NAME; in that case, do not create a
kono
parents:
diff changeset
1904 new SSA_NAME for it. */
kono
parents:
diff changeset
1905
kono
parents:
diff changeset
1906 static tree
kono
parents:
diff changeset
1907 maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1908 bool before_p)
kono
parents:
diff changeset
1909 {
kono
parents:
diff changeset
1910 if (TREE_CODE (base) == SSA_NAME)
kono
parents:
diff changeset
1911 return base;
kono
parents:
diff changeset
1912 gimple *g = gimple_build_assign (make_ssa_name (TREE_TYPE (base)),
kono
parents:
diff changeset
1913 TREE_CODE (base), base);
kono
parents:
diff changeset
1914 gimple_set_location (g, loc);
kono
parents:
diff changeset
1915 if (before_p)
kono
parents:
diff changeset
1916 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1917 else
kono
parents:
diff changeset
1918 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1919 return gimple_assign_lhs (g);
kono
parents:
diff changeset
1920 }
kono
parents:
diff changeset
1921
kono
parents:
diff changeset
1922 /* LEN can already have necessary size and precision;
kono
parents:
diff changeset
1923 in that case, do not create a new variable. */
kono
parents:
diff changeset
1924
kono
parents:
diff changeset
1925 tree
kono
parents:
diff changeset
1926 maybe_cast_to_ptrmode (location_t loc, tree len, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1927 bool before_p)
kono
parents:
diff changeset
1928 {
kono
parents:
diff changeset
1929 if (ptrofftype_p (len))
kono
parents:
diff changeset
1930 return len;
kono
parents:
diff changeset
1931 gimple *g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1932 NOP_EXPR, len);
kono
parents:
diff changeset
1933 gimple_set_location (g, loc);
kono
parents:
diff changeset
1934 if (before_p)
kono
parents:
diff changeset
1935 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1936 else
kono
parents:
diff changeset
1937 gsi_insert_after (iter, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1938 return gimple_assign_lhs (g);
kono
parents:
diff changeset
1939 }
kono
parents:
diff changeset
1940
kono
parents:
diff changeset
1941 /* Instrument the memory access instruction BASE. Insert new
kono
parents:
diff changeset
1942 statements before or after ITER.
kono
parents:
diff changeset
1943
kono
parents:
diff changeset
1944 Note that the memory access represented by BASE can be either an
kono
parents:
diff changeset
1945 SSA_NAME, or a non-SSA expression. LOCATION is the source code
kono
parents:
diff changeset
1946 location. IS_STORE is TRUE for a store, FALSE for a load.
kono
parents:
diff changeset
1947 BEFORE_P is TRUE for inserting the instrumentation code before
kono
parents:
diff changeset
1948 ITER, FALSE for inserting it after ITER. IS_SCALAR_ACCESS is TRUE
kono
parents:
diff changeset
1949 for a scalar memory access and FALSE for memory region access.
kono
parents:
diff changeset
1950 NON_ZERO_P is TRUE if memory region is guaranteed to have non-zero
kono
parents:
diff changeset
1951 length. ALIGN tells alignment of accessed memory object.
kono
parents:
diff changeset
1952
kono
parents:
diff changeset
1953 START_INSTRUMENTED and END_INSTRUMENTED are TRUE if start/end of
kono
parents:
diff changeset
1954 memory region have already been instrumented.
kono
parents:
diff changeset
1955
kono
parents:
diff changeset
1956 If BEFORE_P is TRUE, *ITER is arranged to still point to the
kono
parents:
diff changeset
1957 statement it was pointing to prior to calling this function,
kono
parents:
diff changeset
1958 otherwise, it points to the statement logically following it. */
kono
parents:
diff changeset
1959
kono
parents:
diff changeset
1960 static void
kono
parents:
diff changeset
1961 build_check_stmt (location_t loc, tree base, tree len,
kono
parents:
diff changeset
1962 HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1963 bool is_non_zero_len, bool before_p, bool is_store,
kono
parents:
diff changeset
1964 bool is_scalar_access, unsigned int align = 0)
kono
parents:
diff changeset
1965 {
kono
parents:
diff changeset
1966 gimple_stmt_iterator gsi = *iter;
kono
parents:
diff changeset
1967 gimple *g;
kono
parents:
diff changeset
1968
kono
parents:
diff changeset
1969 gcc_assert (!(size_in_bytes > 0 && !is_non_zero_len));
kono
parents:
diff changeset
1970
kono
parents:
diff changeset
1971 gsi = *iter;
kono
parents:
diff changeset
1972
kono
parents:
diff changeset
1973 base = unshare_expr (base);
kono
parents:
diff changeset
1974 base = maybe_create_ssa_name (loc, base, &gsi, before_p);
kono
parents:
diff changeset
1975
kono
parents:
diff changeset
1976 if (len)
kono
parents:
diff changeset
1977 {
kono
parents:
diff changeset
1978 len = unshare_expr (len);
kono
parents:
diff changeset
1979 len = maybe_cast_to_ptrmode (loc, len, iter, before_p);
kono
parents:
diff changeset
1980 }
kono
parents:
diff changeset
1981 else
kono
parents:
diff changeset
1982 {
kono
parents:
diff changeset
1983 gcc_assert (size_in_bytes != -1);
kono
parents:
diff changeset
1984 len = build_int_cst (pointer_sized_int_node, size_in_bytes);
kono
parents:
diff changeset
1985 }
kono
parents:
diff changeset
1986
kono
parents:
diff changeset
1987 if (size_in_bytes > 1)
kono
parents:
diff changeset
1988 {
kono
parents:
diff changeset
1989 if ((size_in_bytes & (size_in_bytes - 1)) != 0
kono
parents:
diff changeset
1990 || size_in_bytes > 16)
kono
parents:
diff changeset
1991 is_scalar_access = false;
kono
parents:
diff changeset
1992 else if (align && align < size_in_bytes * BITS_PER_UNIT)
kono
parents:
diff changeset
1993 {
kono
parents:
diff changeset
1994 /* On non-strict alignment targets, if
kono
parents:
diff changeset
1995 16-byte access is just 8-byte aligned,
kono
parents:
diff changeset
1996 this will result in misaligned shadow
kono
parents:
diff changeset
1997 memory 2 byte load, but otherwise can
kono
parents:
diff changeset
1998 be handled using one read. */
kono
parents:
diff changeset
1999 if (size_in_bytes != 16
kono
parents:
diff changeset
2000 || STRICT_ALIGNMENT