Mercurial > hg > CbC > CbC_gcc
comparison gcc/gimple-ssa-warn-restrict.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* Pass to detect and issue warnings for violations of the restrict | 1 /* Pass to detect and issue warnings for violations of the restrict |
2 qualifier. | 2 qualifier. |
3 Copyright (C) 2017-2018 Free Software Foundation, Inc. | 3 Copyright (C) 2017-2020 Free Software Foundation, Inc. |
4 Contributed by Martin Sebor <msebor@redhat.com>. | 4 Contributed by Martin Sebor <msebor@redhat.com>. |
5 | 5 |
6 This file is part of GCC. | 6 This file is part of GCC. |
7 | 7 |
8 GCC is free software; you can redistribute it and/or modify it under | 8 GCC is free software; you can redistribute it and/or modify it under |
34 #include "diagnostic-core.h" | 34 #include "diagnostic-core.h" |
35 #include "fold-const.h" | 35 #include "fold-const.h" |
36 #include "gimple-iterator.h" | 36 #include "gimple-iterator.h" |
37 #include "tree-dfa.h" | 37 #include "tree-dfa.h" |
38 #include "tree-ssa.h" | 38 #include "tree-ssa.h" |
39 #include "params.h" | |
40 #include "tree-cfg.h" | 39 #include "tree-cfg.h" |
41 #include "tree-object-size.h" | 40 #include "tree-object-size.h" |
42 #include "calls.h" | 41 #include "calls.h" |
43 #include "cfgloop.h" | 42 #include "cfgloop.h" |
44 #include "intl.h" | 43 #include "intl.h" |
73 }; | 72 }; |
74 | 73 |
75 bool | 74 bool |
76 pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED) | 75 pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED) |
77 { | 76 { |
78 return warn_array_bounds != 0 || warn_restrict != 0; | 77 return warn_array_bounds || warn_restrict || warn_stringop_overflow; |
79 } | 78 } |
80 | 79 |
81 /* Class to walk the basic blocks of a function in dominator order. */ | 80 /* Class to walk the basic blocks of a function in dominator order. */ |
82 class wrestrict_dom_walker : public dom_walker | 81 class wrestrict_dom_walker : public dom_walker |
83 { | 82 { |
122 } | 121 } |
123 | 122 |
124 /* Description of a memory reference by a built-in function. This | 123 /* Description of a memory reference by a built-in function. This |
125 is similar to ao_ref but made especially suitable for -Wrestrict | 124 is similar to ao_ref but made especially suitable for -Wrestrict |
126 and not for optimization. */ | 125 and not for optimization. */ |
127 struct builtin_memref | 126 class builtin_memref |
128 { | 127 { |
128 public: | |
129 /* The original pointer argument to the built-in function. */ | 129 /* The original pointer argument to the built-in function. */ |
130 tree ptr; | 130 tree ptr; |
131 /* The referenced subobject or NULL if not available, and the base | 131 /* The referenced subobject or NULL if not available, and the base |
132 object of the memory reference or NULL. */ | 132 object of the memory reference or NULL. */ |
133 tree ref; | 133 tree ref; |
134 tree base; | 134 tree base; |
135 | 135 |
136 /* The size of the BASE object, PTRDIFF_MAX if indeterminate, | 136 /* The size of the BASE object, PTRDIFF_MAX if indeterminate, |
137 and negative until (possibly lazily) initialized. */ | 137 and negative until (possibly lazily) initialized. */ |
138 offset_int basesize; | 138 offset_int basesize; |
139 /* Same for the subobject. */ | |
140 offset_int refsize; | |
139 | 141 |
140 /* The non-negative offset of the referenced subobject. Used to avoid | 142 /* The non-negative offset of the referenced subobject. Used to avoid |
141 warnings for (apparently) possibly but not definitively overlapping | 143 warnings for (apparently) possibly but not definitively overlapping |
142 accesses to member arrays. Negative when unknown/invalid. */ | 144 accesses to member arrays. Negative when unknown/invalid. */ |
143 offset_int refoff; | 145 offset_int refoff; |
144 | 146 |
145 /* The offset range relative to the base. */ | 147 /* The offset range relative to the base. */ |
146 offset_int offrange[2]; | 148 offset_int offrange[2]; |
147 /* The size range of the access to this reference. */ | 149 /* The size range of the access to this reference. */ |
148 offset_int sizrange[2]; | 150 offset_int sizrange[2]; |
151 | |
152 /* Cached result of get_max_objsize(). */ | |
153 const offset_int maxobjsize; | |
149 | 154 |
150 /* True for "bounded" string functions like strncat, and strncpy | 155 /* True for "bounded" string functions like strncat, and strncpy |
151 and their variants that specify either an exact or upper bound | 156 and their variants that specify either an exact or upper bound |
152 on the size of the accesses they perform. For strncat both | 157 on the size of the accesses they perform. For strncat both |
153 the source and destination references are bounded. For strncpy | 158 the source and destination references are bounded. For strncpy |
154 only the destination reference is. */ | 159 only the destination reference is. */ |
155 bool strbounded_p; | 160 bool strbounded_p; |
156 | 161 |
157 builtin_memref (tree, tree); | 162 builtin_memref (tree, tree); |
158 | 163 |
159 tree offset_out_of_bounds (int, offset_int[2]) const; | 164 tree offset_out_of_bounds (int, offset_int[3]) const; |
160 | 165 |
161 private: | 166 private: |
162 | 167 |
163 /* Ctor helper to set or extend OFFRANGE based on argument. */ | 168 /* Ctor helper to set or extend OFFRANGE based on argument. */ |
164 void extend_offset_range (tree); | 169 void extend_offset_range (tree); |
186 | 191 |
187 /* True to consider valid only accesses to the smallest subobject | 192 /* True to consider valid only accesses to the smallest subobject |
188 and false for raw memory functions. */ | 193 and false for raw memory functions. */ |
189 bool strict () const | 194 bool strict () const |
190 { | 195 { |
191 return detect_overlap != &builtin_access::generic_overlap; | 196 return (detect_overlap != &builtin_access::generic_overlap |
197 && detect_overlap != &builtin_access::no_overlap); | |
192 } | 198 } |
193 | 199 |
194 builtin_access (gimple *, builtin_memref &, builtin_memref &); | 200 builtin_access (gimple *, builtin_memref &, builtin_memref &); |
195 | 201 |
196 /* Entry point to determine overlap. */ | 202 /* Entry point to determine overlap. */ |
197 bool overlap (); | 203 bool overlap (); |
204 | |
205 offset_int write_off (tree) const; | |
206 | |
207 void dump (FILE *) const; | |
198 | 208 |
199 private: | 209 private: |
200 /* Implementation functions used to determine overlap. */ | 210 /* Implementation functions used to determine overlap. */ |
201 bool generic_overlap (); | 211 bool generic_overlap (); |
202 bool strcat_overlap (); | 212 bool strcat_overlap (); |
228 builtin_memref::builtin_memref (tree expr, tree size) | 238 builtin_memref::builtin_memref (tree expr, tree size) |
229 : ptr (expr), | 239 : ptr (expr), |
230 ref (), | 240 ref (), |
231 base (), | 241 base (), |
232 basesize (-1), | 242 basesize (-1), |
243 refsize (-1), | |
233 refoff (HOST_WIDE_INT_MIN), | 244 refoff (HOST_WIDE_INT_MIN), |
234 offrange (), | 245 offrange (), |
235 sizrange (), | 246 sizrange (), |
247 maxobjsize (tree_to_shwi (max_object_size ())), | |
236 strbounded_p () | 248 strbounded_p () |
237 { | 249 { |
238 /* Unfortunately, wide_int default ctor is a no-op so array members | 250 /* Unfortunately, wide_int default ctor is a no-op so array members |
239 of the type must be set individually. */ | 251 of the type must be set individually. */ |
240 offrange[0] = offrange[1] = 0; | 252 offrange[0] = offrange[1] = 0; |
241 sizrange[0] = sizrange[1] = 0; | 253 sizrange[0] = sizrange[1] = 0; |
242 | 254 |
243 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 255 if (!expr) |
256 return; | |
244 | 257 |
245 /* Find the BASE object or pointer referenced by EXPR and set | 258 /* Find the BASE object or pointer referenced by EXPR and set |
246 the offset range OFFRANGE in the process. */ | 259 the offset range OFFRANGE in the process. */ |
247 set_base_and_offset (expr); | 260 set_base_and_offset (expr); |
248 | 261 |
254 get_size_range (size, range, true); | 267 get_size_range (size, range, true); |
255 sizrange[0] = wi::to_offset (range[0]); | 268 sizrange[0] = wi::to_offset (range[0]); |
256 sizrange[1] = wi::to_offset (range[1]); | 269 sizrange[1] = wi::to_offset (range[1]); |
257 /* get_size_range returns SIZE_MAX for the maximum size. | 270 /* get_size_range returns SIZE_MAX for the maximum size. |
258 Constrain it to the real maximum of PTRDIFF_MAX. */ | 271 Constrain it to the real maximum of PTRDIFF_MAX. */ |
259 if (sizrange[1] > maxobjsize) | 272 if (sizrange[0] <= maxobjsize && sizrange[1] > maxobjsize) |
260 sizrange[1] = maxobjsize; | 273 sizrange[1] = maxobjsize; |
261 } | 274 } |
262 else | 275 else |
263 sizrange[1] = maxobjsize; | 276 sizrange[1] = maxobjsize; |
264 | 277 |
270 if (offrange[0] < 0 && offrange[1] > 0) | 283 if (offrange[0] < 0 && offrange[1] > 0) |
271 offrange[0] = 0; | 284 offrange[0] = 0; |
272 | 285 |
273 offset_int maxoff = maxobjsize; | 286 offset_int maxoff = maxobjsize; |
274 tree basetype = TREE_TYPE (base); | 287 tree basetype = TREE_TYPE (base); |
275 if (TREE_CODE (basetype) == ARRAY_TYPE | 288 if (TREE_CODE (basetype) == ARRAY_TYPE) |
276 && ref | 289 { |
277 && array_at_struct_end_p (ref)) | 290 if (ref && array_at_struct_end_p (ref)) |
278 ; /* Use the maximum possible offset for last member arrays. */ | 291 ; /* Use the maximum possible offset for last member arrays. */ |
279 else if (tree basesize = TYPE_SIZE_UNIT (basetype)) | 292 else if (tree basesize = TYPE_SIZE_UNIT (basetype)) |
280 if (TREE_CODE (basesize) == INTEGER_CST) | 293 if (TREE_CODE (basesize) == INTEGER_CST) |
281 /* Size could be non-constant for a variable-length type such | 294 /* Size could be non-constant for a variable-length type such |
282 as a struct with a VLA member (a GCC extension). */ | 295 as a struct with a VLA member (a GCC extension). */ |
283 maxoff = wi::to_offset (basesize); | 296 maxoff = wi::to_offset (basesize); |
297 } | |
284 | 298 |
285 if (offrange[0] >= 0) | 299 if (offrange[0] >= 0) |
286 { | 300 { |
287 if (offrange[1] < 0) | 301 if (offrange[1] < 0) |
288 offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize; | 302 offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize; |
289 else if (offrange[0] <= maxoff && offrange[1] > maxoff) | 303 else if (offrange[0] <= maxoff && offrange[1] > maxoff) |
290 offrange[1] = maxoff; | 304 offrange[1] = maxoff; |
291 } | 305 } |
292 } | 306 } |
293 | 307 |
294 /* Ctor helper to set or extend OFFRANGE based on the OFFSET argument. */ | 308 /* Based on the initial length of the destination STARTLEN, returns |
309 the offset of the first write access from the beginning of | |
310 the destination. Nonzero only for strcat-type of calls. */ | |
311 | |
312 offset_int builtin_access::write_off (tree startlen) const | |
313 { | |
314 if (detect_overlap != &builtin_access::strcat_overlap | |
315 || !startlen || TREE_CODE (startlen) != INTEGER_CST) | |
316 return 0; | |
317 | |
318 return wi::to_offset (startlen); | |
319 } | |
320 | |
321 /* Ctor helper to set or extend OFFRANGE based on the OFFSET argument. | |
322 Pointer offsets are represented as unsigned sizetype but must be | |
323 treated as signed. */ | |
295 | 324 |
296 void | 325 void |
297 builtin_memref::extend_offset_range (tree offset) | 326 builtin_memref::extend_offset_range (tree offset) |
298 { | 327 { |
299 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | |
300 | |
301 if (TREE_CODE (offset) == INTEGER_CST) | 328 if (TREE_CODE (offset) == INTEGER_CST) |
302 { | 329 { |
303 offset_int off = int_cst_value (offset); | 330 offset_int off = int_cst_value (offset); |
304 if (off != 0) | 331 if (off != 0) |
305 { | 332 { |
309 return; | 336 return; |
310 } | 337 } |
311 | 338 |
312 if (TREE_CODE (offset) == SSA_NAME) | 339 if (TREE_CODE (offset) == SSA_NAME) |
313 { | 340 { |
341 /* A pointer offset is represented as sizetype but treated | |
342 as signed. */ | |
314 wide_int min, max; | 343 wide_int min, max; |
315 value_range_kind rng = get_range_info (offset, &min, &max); | 344 value_range_kind rng = get_range_info (offset, &min, &max); |
316 if (rng == VR_RANGE) | 345 if (rng == VR_ANTI_RANGE && wi::lts_p (max, min)) |
317 { | 346 { |
347 /* Convert an anti-range whose upper bound is less than | |
348 its lower bound to a signed range. */ | |
349 offrange[0] += offset_int::from (max + 1, SIGNED); | |
350 offrange[1] += offset_int::from (min - 1, SIGNED); | |
351 return; | |
352 } | |
353 | |
354 if (rng == VR_RANGE | |
355 && (DECL_P (base) || wi::lts_p (min, max))) | |
356 { | |
357 /* Preserve the bounds of the range for an offset into | |
358 a known object (it may be adjusted later relative to | |
359 a constant offset from its beginning). Otherwise use | |
360 the bounds only when they are ascending when treated | |
361 as signed. */ | |
318 offrange[0] += offset_int::from (min, SIGNED); | 362 offrange[0] += offset_int::from (min, SIGNED); |
319 offrange[1] += offset_int::from (max, SIGNED); | 363 offrange[1] += offset_int::from (max, SIGNED); |
320 } | 364 return; |
321 else if (rng == VR_ANTI_RANGE) | 365 } |
322 { | 366 |
323 offrange[0] += offset_int::from (max + 1, SIGNED); | 367 /* Handle an anti-range the same as no range at all. */ |
324 offrange[1] += offset_int::from (min - 1, SIGNED); | 368 gimple *stmt = SSA_NAME_DEF_STMT (offset); |
325 } | 369 tree type; |
326 else | 370 if (is_gimple_assign (stmt) |
327 { | 371 && (type = TREE_TYPE (gimple_assign_rhs1 (stmt))) |
328 gimple *stmt = SSA_NAME_DEF_STMT (offset); | 372 && INTEGRAL_TYPE_P (type)) |
329 tree type; | 373 { |
330 if (is_gimple_assign (stmt) | 374 tree_code code = gimple_assign_rhs_code (stmt); |
331 && gimple_assign_rhs_code (stmt) == NOP_EXPR | 375 if (code == NOP_EXPR) |
332 && (type = TREE_TYPE (gimple_assign_rhs1 (stmt))) | |
333 && INTEGRAL_TYPE_P (type)) | |
334 { | 376 { |
335 /* Use the bounds of the type of the NOP_EXPR operand | 377 /* Use the bounds of the type of the NOP_EXPR operand |
336 even if it's signed. The result doesn't trigger | 378 even if it's signed. The result doesn't trigger |
337 warnings but makes their output more readable. */ | 379 warnings but makes their output more readable. */ |
338 offrange[0] += wi::to_offset (TYPE_MIN_VALUE (type)); | 380 offrange[0] += wi::to_offset (TYPE_MIN_VALUE (type)); |
339 offrange[1] += wi::to_offset (TYPE_MAX_VALUE (type)); | 381 offrange[1] += wi::to_offset (TYPE_MAX_VALUE (type)); |
382 return; | |
340 } | 383 } |
341 else | 384 } |
342 offrange[1] += maxobjsize; | 385 } |
343 } | 386 |
344 return; | 387 const offset_int maxoff = tree_to_shwi (max_object_size ()) >> 1; |
345 } | 388 const offset_int minoff = -maxoff - 1; |
346 | 389 |
347 offrange[1] += maxobjsize; | 390 offrange[0] += minoff; |
391 offrange[1] += maxoff; | |
348 } | 392 } |
349 | 393 |
350 /* Determines the base object or pointer of the reference EXPR | 394 /* Determines the base object or pointer of the reference EXPR |
351 and the offset range from the beginning of the base. */ | 395 and the offset range from the beginning of the base. */ |
352 | 396 |
353 void | 397 void |
354 builtin_memref::set_base_and_offset (tree expr) | 398 builtin_memref::set_base_and_offset (tree expr) |
355 { | 399 { |
356 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 400 tree offset = NULL_TREE; |
357 | 401 |
358 if (TREE_CODE (expr) == SSA_NAME) | 402 if (TREE_CODE (expr) == SSA_NAME) |
359 { | 403 { |
360 /* Try to tease the offset out of the pointer. */ | 404 /* Try to tease the offset out of the pointer. */ |
361 gimple *stmt = SSA_NAME_DEF_STMT (expr); | 405 gimple *stmt = SSA_NAME_DEF_STMT (expr); |
378 } | 422 } |
379 } | 423 } |
380 else if (code == POINTER_PLUS_EXPR) | 424 else if (code == POINTER_PLUS_EXPR) |
381 { | 425 { |
382 expr = gimple_assign_rhs1 (stmt); | 426 expr = gimple_assign_rhs1 (stmt); |
383 | 427 offset = gimple_assign_rhs2 (stmt); |
384 tree offset = gimple_assign_rhs2 (stmt); | |
385 extend_offset_range (offset); | |
386 } | 428 } |
387 else | 429 else |
388 { | 430 { |
389 base = expr; | 431 base = expr; |
390 return; | 432 return; |
391 } | 433 } |
392 } | 434 } |
393 else | 435 else |
394 { | 436 { |
437 /* FIXME: Handle PHI nodes in case like: | |
438 _12 = &MEM[(void *)&a + 2B] + _10; | |
439 | |
440 <bb> [local count: 1073741824]: | |
441 # prephitmp_13 = PHI <_12, &MEM[(void *)&a + 2B]> | |
442 memcpy (prephitmp_13, p_7(D), 6); */ | |
395 base = expr; | 443 base = expr; |
396 return; | 444 return; |
397 } | 445 } |
398 } | 446 } |
399 | 447 |
417 &mode, &sign, &reverse, &vol); | 465 &mode, &sign, &reverse, &vol); |
418 | 466 |
419 /* get_inner_reference is not expected to return null. */ | 467 /* get_inner_reference is not expected to return null. */ |
420 gcc_assert (base != NULL); | 468 gcc_assert (base != NULL); |
421 | 469 |
470 if (offset) | |
471 extend_offset_range (offset); | |
472 | |
422 poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT); | 473 poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT); |
423 | 474 |
424 /* Convert the poly_int64 offset to offset_int. The offset | 475 /* Convert the poly_int64 offset to offset_int. The offset |
425 should be constant but be prepared for it not to be just in | 476 should be constant but be prepared for it not to be just in |
426 case. */ | 477 case. */ |
450 offrange[1] += maxobjsize; | 501 offrange[1] += maxobjsize; |
451 } | 502 } |
452 | 503 |
453 if (TREE_CODE (base) == MEM_REF) | 504 if (TREE_CODE (base) == MEM_REF) |
454 { | 505 { |
455 tree memrefoff = TREE_OPERAND (base, 1); | 506 tree memrefoff = fold_convert (ptrdiff_type_node, TREE_OPERAND (base, 1)); |
456 extend_offset_range (memrefoff); | 507 extend_offset_range (memrefoff); |
457 base = TREE_OPERAND (base, 0); | 508 base = TREE_OPERAND (base, 0); |
458 } | 509 |
510 if (refoff != HOST_WIDE_INT_MIN | |
511 && TREE_CODE (expr) == COMPONENT_REF) | |
512 { | |
513 /* Bump up the offset of the referenced subobject to reflect | |
514 the offset to the enclosing object. For example, so that | |
515 in | |
516 struct S { char a, b[3]; } s[2]; | |
517 strcpy (s[1].b, "1234"); | |
518 REFOFF is set to s[1].b - (char*)s. */ | |
519 offset_int off = tree_to_shwi (memrefoff); | |
520 refoff += off; | |
521 } | |
522 | |
523 if (!integer_zerop (memrefoff)) | |
524 /* A non-zero offset into an array of struct with flexible array | |
525 members implies that the array is empty because there is no | |
526 way to initialize such a member when it belongs to an array. | |
527 This must be some sort of a bug. */ | |
528 refsize = 0; | |
529 } | |
530 | |
531 if (TREE_CODE (ref) == COMPONENT_REF) | |
532 if (tree size = component_ref_size (ref)) | |
533 if (TREE_CODE (size) == INTEGER_CST) | |
534 refsize = wi::to_offset (size); | |
459 | 535 |
460 if (TREE_CODE (base) == SSA_NAME) | 536 if (TREE_CODE (base) == SSA_NAME) |
461 set_base_and_offset (base); | 537 set_base_and_offset (base); |
462 } | 538 } |
463 | 539 |
464 /* Return error_mark_node if the signed offset exceeds the bounds | 540 /* Return error_mark_node if the signed offset exceeds the bounds |
465 of the address space (PTRDIFF_MAX). Otherwise, return either | 541 of the address space (PTRDIFF_MAX). Otherwise, return either BASE |
466 BASE or REF when the offset exceeds the bounds of the BASE or | 542 or REF when the offset exceeds the bounds of the BASE or REF object, |
467 REF object, and set OOBOFF to the past-the-end offset formed | 543 and set OOBOFF to the past-the-end offset formed by the reference, |
468 by the reference, including its size. When STRICT is non-zero | 544 including its size. OOBOFF is initially setto the range of offsets, |
469 use REF size, when available, otherwise use BASE size. When | 545 and OOBOFF[2] to the offset of the first write access (nonzero for |
470 STRICT is greater than 1, use the size of the last array member | 546 the strcat family). When STRICT is nonzero use REF size, when |
471 as the bound, otherwise treat such a member as a flexible array | 547 available, otherwise use BASE size. When STRICT is greater than 1, |
472 member. Return NULL when the offset is in bounds. */ | 548 use the size of the last array member as the bound, otherwise treat |
549 such a member as a flexible array member. Return NULL when the offset | |
550 is in bounds. */ | |
473 | 551 |
474 tree | 552 tree |
475 builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[2]) const | 553 builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[3]) const |
476 { | 554 { |
477 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 555 if (!ptr) |
556 return NULL_TREE; | |
557 | |
558 /* The offset of the first write access or zero. */ | |
559 offset_int wroff = ooboff[2]; | |
478 | 560 |
479 /* A temporary, possibly adjusted, copy of the offset range. */ | 561 /* A temporary, possibly adjusted, copy of the offset range. */ |
480 offset_int offrng[2] = { offrange[0], offrange[1] }; | 562 offset_int offrng[2] = { ooboff[0], ooboff[1] }; |
481 | 563 |
482 if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE) | 564 if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE) |
483 { | 565 { |
484 /* Check for offset in an anti-range with a negative lower bound. | 566 /* Check for offset in an anti-range with a negative lower bound. |
485 For such a range, consider only the non-negative subrange. */ | 567 For such a range, consider only the non-negative subrange. */ |
493 /* The bounds need not be ordered. Set HIB to use as the index | 575 /* The bounds need not be ordered. Set HIB to use as the index |
494 of the larger of the bounds and LOB as the opposite. */ | 576 of the larger of the bounds and LOB as the opposite. */ |
495 bool hib = wi::les_p (offrng[0], offrng[1]); | 577 bool hib = wi::les_p (offrng[0], offrng[1]); |
496 bool lob = !hib; | 578 bool lob = !hib; |
497 | 579 |
580 /* Set to the size remaining in the object object after subtracting | |
581 REFOFF. It may become negative as a result of negative indices | |
582 into the enclosing object, such as in: | |
583 extern struct S { char a[4], b[3], c[1]; } *p; | |
584 strcpy (p[-3].b, "123"); */ | |
585 offset_int size = basesize; | |
586 tree obj = base; | |
587 | |
588 const bool decl_p = DECL_P (obj); | |
589 | |
498 if (basesize < 0) | 590 if (basesize < 0) |
499 { | 591 { |
500 endoff = offrng[lob] + sizrange[0]; | 592 endoff = offrng[lob] + (sizrange[0] - wroff); |
501 | 593 |
502 /* For a reference through a pointer to an object of unknown size | 594 /* For a reference through a pointer to an object of unknown size |
503 all initial offsets are considered valid, positive as well as | 595 all initial offsets are considered valid, positive as well as |
504 negative, since the pointer itself can point past the beginning | 596 negative, since the pointer itself can point past the beginning |
505 of the object. However, the sum of the lower bound of the offset | 597 of the object. However, the sum of the lower bound of the offset |
506 and that of the size must be less than or equal than PTRDIFF_MAX. */ | 598 and that of the size must be less than or equal than PTRDIFF_MAX. */ |
507 if (endoff > maxobjsize) | 599 if (endoff > maxobjsize) |
508 return error_mark_node; | 600 return error_mark_node; |
509 | 601 |
510 return NULL_TREE; | 602 /* When the referenced subobject is known, the end offset must be |
603 within its bounds. Otherwise there is nothing to do. */ | |
604 if (strict | |
605 && !decl_p | |
606 && ref | |
607 && refsize >= 0 | |
608 && TREE_CODE (ref) == COMPONENT_REF) | |
609 { | |
610 /* If REFOFF is negative, SIZE will become negative here. */ | |
611 size = refoff + refsize; | |
612 obj = ref; | |
613 } | |
614 else | |
615 return NULL_TREE; | |
511 } | 616 } |
512 | 617 |
513 /* A reference to an object of known size must be within the bounds | 618 /* A reference to an object of known size must be within the bounds |
514 of the base object. */ | 619 of either the base object or the subobject (see above for when |
515 if (offrng[hib] < 0 || offrng[lob] > basesize) | 620 a subobject can be used). */ |
516 return base; | 621 if ((decl_p && offrng[hib] < 0) || offrng[lob] > size) |
622 return obj; | |
517 | 623 |
518 /* The extent of the reference must also be within the bounds of | 624 /* The extent of the reference must also be within the bounds of |
519 the base object (if known) or the maximum object size otherwise. */ | 625 the base object (if known) or the subobject or the maximum object |
520 endoff = wi::smax (offrng[lob], 0) + sizrange[0]; | 626 size otherwise. */ |
627 endoff = offrng[lob] + sizrange[0]; | |
521 if (endoff > maxobjsize) | 628 if (endoff > maxobjsize) |
522 return error_mark_node; | 629 return error_mark_node; |
523 | 630 |
524 offset_int size = basesize; | |
525 tree obj = base; | |
526 | |
527 if (strict | 631 if (strict |
528 && DECL_P (obj) | 632 && decl_p |
529 && ref | 633 && ref |
530 && refoff >= 0 | 634 && refsize >= 0 |
531 && TREE_CODE (ref) == COMPONENT_REF | 635 && TREE_CODE (ref) == COMPONENT_REF) |
532 && (strict > 1 | 636 { |
533 || !array_at_struct_end_p (ref))) | 637 /* If the reference is to a member subobject of a declared object, |
534 { | 638 the offset must be within the bounds of the subobject. */ |
535 /* If the reference is to a member subobject, the offset must | 639 size = refoff + refsize; |
536 be within the bounds of the subobject. */ | 640 obj = ref; |
537 tree field = TREE_OPERAND (ref, 1); | |
538 tree type = TREE_TYPE (field); | |
539 if (tree sz = TYPE_SIZE_UNIT (type)) | |
540 if (TREE_CODE (sz) == INTEGER_CST) | |
541 { | |
542 size = refoff + wi::to_offset (sz); | |
543 obj = ref; | |
544 } | |
545 } | 641 } |
546 | 642 |
547 if (endoff <= size) | 643 if (endoff <= size) |
548 return NULL_TREE; | 644 return NULL_TREE; |
549 | 645 |
550 /* Set the out-of-bounds offset range to be one greater than | 646 /* Set the out-of-bounds offset range to be one greater than |
551 that delimited by the reference including its size. */ | 647 that delimited by the reference including its size. */ |
552 ooboff[lob] = size + 1; | 648 ooboff[lob] = size; |
553 | 649 |
554 if (endoff > ooboff[lob]) | 650 if (endoff > ooboff[lob]) |
555 ooboff[hib] = endoff; | 651 ooboff[hib] = endoff - 1; |
556 else | 652 else |
557 ooboff[hib] = wi::smax (offrng[lob], 0) + sizrange[1]; | 653 ooboff[hib] = offrng[lob] + sizrange[1]; |
558 | 654 |
559 return obj; | 655 return obj; |
560 } | 656 } |
561 | 657 |
562 /* Create an association between the memory references DST and SRC | 658 /* Create an association between the memory references DST and SRC |
565 builtin_access::builtin_access (gimple *call, builtin_memref &dst, | 661 builtin_access::builtin_access (gimple *call, builtin_memref &dst, |
566 builtin_memref &src) | 662 builtin_memref &src) |
567 : dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (), | 663 : dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (), |
568 dstoff (), srcoff (), dstsiz (), srcsiz () | 664 dstoff (), srcoff (), dstsiz (), srcsiz () |
569 { | 665 { |
666 dstoff[0] = dst.offrange[0]; | |
667 dstoff[1] = dst.offrange[1]; | |
668 | |
570 /* Zero out since the offset_int ctors invoked above are no-op. */ | 669 /* Zero out since the offset_int ctors invoked above are no-op. */ |
571 dstoff[0] = dstoff[1] = 0; | |
572 srcoff[0] = srcoff[1] = 0; | 670 srcoff[0] = srcoff[1] = 0; |
573 dstsiz[0] = dstsiz[1] = 0; | 671 dstsiz[0] = dstsiz[1] = 0; |
574 srcsiz[0] = srcsiz[1] = 0; | 672 srcsiz[0] = srcsiz[1] = 0; |
575 | 673 |
576 /* Object Size Type to use to determine the size of the destination | 674 /* Object Size Type to use to determine the size of the destination |
607 ostype = 0; | 705 ostype = 0; |
608 depends_p = false; | 706 depends_p = false; |
609 detect_overlap = &builtin_access::no_overlap; | 707 detect_overlap = &builtin_access::no_overlap; |
610 break; | 708 break; |
611 | 709 |
710 case BUILT_IN_MEMSET: | |
711 case BUILT_IN_MEMSET_CHK: | |
712 /* For memset there is never any overlap to check for. */ | |
713 ostype = 0; | |
714 depends_p = false; | |
715 detect_overlap = &builtin_access::no_overlap; | |
716 break; | |
717 | |
612 case BUILT_IN_STPNCPY: | 718 case BUILT_IN_STPNCPY: |
613 case BUILT_IN_STPNCPY_CHK: | 719 case BUILT_IN_STPNCPY_CHK: |
614 case BUILT_IN_STRNCPY: | 720 case BUILT_IN_STRNCPY: |
615 case BUILT_IN_STRNCPY_CHK: | 721 case BUILT_IN_STRNCPY_CHK: |
616 dstref->strbounded_p = true; | 722 dstref->strbounded_p = true; |
641 to be validated for in-bounds offsets and non-overlapping | 747 to be validated for in-bounds offsets and non-overlapping |
642 copies. */ | 748 copies. */ |
643 return; | 749 return; |
644 } | 750 } |
645 | 751 |
646 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 752 const offset_int maxobjsize = dst.maxobjsize; |
647 | 753 |
648 /* Try to determine the size of the base object. compute_objsize | 754 /* Try to determine the size of the base object. compute_objsize |
649 expects a pointer so create one if BASE is a non-pointer object. */ | 755 expects a pointer so create one if BASE is a non-pointer object. */ |
650 tree addr; | 756 tree addr; |
651 if (dst.basesize < 0) | 757 if (dst.basesize < 0) |
660 dst.basesize = HOST_WIDE_INT_MIN; | 766 dst.basesize = HOST_WIDE_INT_MIN; |
661 else | 767 else |
662 dst.basesize = maxobjsize; | 768 dst.basesize = maxobjsize; |
663 } | 769 } |
664 | 770 |
665 if (src.basesize < 0) | 771 if (src.base && src.basesize < 0) |
666 { | 772 { |
667 addr = src.base; | 773 addr = src.base; |
668 if (!POINTER_TYPE_P (TREE_TYPE (addr))) | 774 if (!POINTER_TYPE_P (TREE_TYPE (addr))) |
669 addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr); | 775 addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr); |
670 | 776 |
674 src.basesize = HOST_WIDE_INT_MIN; | 780 src.basesize = HOST_WIDE_INT_MIN; |
675 else | 781 else |
676 src.basesize = maxobjsize; | 782 src.basesize = maxobjsize; |
677 } | 783 } |
678 | 784 |
679 /* If there is no dependency between the references or the base | 785 /* Make adjustments for references to the same object by string |
680 objects of the two references aren't the same there's nothing | 786 built-in functions to reflect the constraints imposed by |
681 else to do. */ | 787 the function. */ |
682 if (depends_p && dstref->base != srcref->base) | |
683 return; | |
684 | |
685 /* ...otherwise, make adjustments for references to the same object | |
686 by string built-in functions to reflect the constraints imposed | |
687 by the function. */ | |
688 | 788 |
689 /* For bounded string functions determine the range of the bound | 789 /* For bounded string functions determine the range of the bound |
690 on the access. For others, the range stays unbounded. */ | 790 on the access. For others, the range stays unbounded. */ |
691 offset_int bounds[2] = { maxobjsize, maxobjsize }; | 791 offset_int bounds[2] = { maxobjsize, maxobjsize }; |
692 if (dstref->strbounded_p) | 792 if (dstref->strbounded_p) |
693 { | 793 { |
794 unsigned nargs = gimple_call_num_args (call); | |
795 if (nargs <= sizeargno) | |
796 return; | |
797 | |
694 tree size = gimple_call_arg (call, sizeargno); | 798 tree size = gimple_call_arg (call, sizeargno); |
695 tree range[2]; | 799 tree range[2]; |
696 if (get_size_range (size, range, true)) | 800 if (get_size_range (size, range, true)) |
697 { | 801 { |
698 bounds[0] = wi::to_offset (range[0]); | 802 bounds[0] = wi::to_offset (range[0]); |
709 dstref->sizrange[0] = bounds[0]; | 813 dstref->sizrange[0] = bounds[0]; |
710 dstref->sizrange[1] = bounds[1]; | 814 dstref->sizrange[1] = bounds[1]; |
711 } | 815 } |
712 } | 816 } |
713 | 817 |
818 bool dstsize_set = false; | |
714 /* The size range of one reference involving the same base object | 819 /* The size range of one reference involving the same base object |
715 can be determined from the size range of the other reference. | 820 can be determined from the size range of the other reference. |
716 This makes it possible to compute accurate offsets for warnings | 821 This makes it possible to compute accurate offsets for warnings |
717 involving functions like strcpy where the length of just one of | 822 involving functions like strcpy where the length of just one of |
718 the two arguments is known (determined by tree-ssa-strlen). */ | 823 the two arguments is known (determined by tree-ssa-strlen). */ |
720 { | 825 { |
721 /* When the destination size is unknown set it to the size of | 826 /* When the destination size is unknown set it to the size of |
722 the source. */ | 827 the source. */ |
723 dstref->sizrange[0] = srcref->sizrange[0]; | 828 dstref->sizrange[0] = srcref->sizrange[0]; |
724 dstref->sizrange[1] = srcref->sizrange[1]; | 829 dstref->sizrange[1] = srcref->sizrange[1]; |
830 dstsize_set = true; | |
725 } | 831 } |
726 else if (srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize) | 832 else if (srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize) |
727 { | 833 { |
728 /* When the source size is unknown set it to the size of | 834 /* When the source size is unknown set it to the size of |
729 the destination. */ | 835 the destination. */ |
732 | 838 |
733 if (depends_p) | 839 if (depends_p) |
734 { | 840 { |
735 if (dstref->strbounded_p) | 841 if (dstref->strbounded_p) |
736 { | 842 { |
737 /* Read access by strncpy is bounded. */ | 843 /* Read access by strncpy is constrained by the third |
738 if (bounds[0] < srcref->sizrange[0]) | 844 argument but except for a zero bound is at least one. */ |
739 srcref->sizrange[0] = bounds[0]; | 845 offset_int size = wi::umax (srcref->basesize, 1); |
740 if (bounds[1] < srcref->sizrange[1]) | 846 offset_int bound = wi::umin (size, bounds[0]); |
741 srcref->sizrange[1] = bounds[1]; | 847 if (bound < srcref->sizrange[0]) |
848 srcref->sizrange[0] = bound; | |
849 bound = wi::umin (srcref->basesize, bounds[1]); | |
850 if (bound < srcref->sizrange[1]) | |
851 srcref->sizrange[1] = bound; | |
742 } | 852 } |
743 | 853 |
744 /* For string functions, adjust the size range of the source | 854 /* For string functions, adjust the size range of the source |
745 reference by the inverse boundaries of the offset (because | 855 reference by the inverse boundaries of the offset (because |
746 the higher the offset into the string the shorter its | 856 the higher the offset into the string the shorter its |
788 dstref->sizrange[0] = srcref->sizrange[0]; | 898 dstref->sizrange[0] = srcref->sizrange[0]; |
789 dstref->sizrange[1] = srcref->sizrange[1]; | 899 dstref->sizrange[1] = srcref->sizrange[1]; |
790 } | 900 } |
791 } | 901 } |
792 } | 902 } |
903 else if (!dstsize_set && detect_overlap == &builtin_access::strcat_overlap) | |
904 { | |
905 dstref->sizrange[0] += srcref->sizrange[0] - 1; | |
906 dstref->sizrange[1] += srcref->sizrange[1] - 1; | |
907 } | |
793 | 908 |
794 if (dstref->strbounded_p) | 909 if (dstref->strbounded_p) |
795 { | 910 { |
796 /* For strncpy, adjust the destination size range to match that | 911 /* For strncpy, adjust the destination size range to match that |
797 of the source computed above. */ | 912 of the source computed above. */ |
846 const builtin_memref *dstref = acs.dstref; | 961 const builtin_memref *dstref = acs.dstref; |
847 const builtin_memref *srcref = acs.srcref; | 962 const builtin_memref *srcref = acs.srcref; |
848 | 963 |
849 gcc_assert (dstref->base == srcref->base); | 964 gcc_assert (dstref->base == srcref->base); |
850 | 965 |
851 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 966 const offset_int maxobjsize = acs.dstref->maxobjsize; |
852 | 967 |
853 offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; | 968 offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; |
854 gcc_assert (maxsize <= maxobjsize); | |
855 | 969 |
856 /* Adjust the larger bounds of the offsets (which may be the first | 970 /* Adjust the larger bounds of the offsets (which may be the first |
857 element if the lower bound is larger than the upper bound) to | 971 element if the lower bound is larger than the upper bound) to |
858 make them valid for the smallest access (if possible) but no smaller | 972 make them valid for the smallest access (if possible) but no smaller |
859 than the smaller bounds. */ | 973 than the smaller bounds. */ |
1055 const builtin_memref *dstref = acs.dstref; | 1169 const builtin_memref *dstref = acs.dstref; |
1056 const builtin_memref *srcref = acs.srcref; | 1170 const builtin_memref *srcref = acs.srcref; |
1057 | 1171 |
1058 gcc_assert (dstref->base == srcref->base); | 1172 gcc_assert (dstref->base == srcref->base); |
1059 | 1173 |
1060 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 1174 const offset_int maxobjsize = acs.dstref->maxobjsize; |
1061 | 1175 |
1062 gcc_assert (dstref->base && dstref->base == srcref->base); | 1176 gcc_assert (dstref->base && dstref->base == srcref->base); |
1063 | 1177 |
1064 /* Adjust for strcat-like accesses. */ | 1178 /* Adjust for strcat-like accesses. */ |
1065 | 1179 |
1066 /* As a special case for strcat, set the DSTREF offsets to the length | 1180 /* As a special case for strcat, set the DSTREF offsets to the length |
1067 of the source string since the function starts writing at the first | 1181 of the destination string since the function starts writing over |
1068 nul, and set the size to 1 for the length of the nul. */ | 1182 its terminating nul, and set the destination size to 1 for the length |
1069 acs.dstoff[0] += acs.dstsiz[0]; | 1183 of the nul. */ |
1070 acs.dstoff[1] += acs.dstsiz[1]; | 1184 acs.dstoff[0] += dstsiz[0] - srcref->sizrange[0]; |
1185 acs.dstoff[1] += dstsiz[1] - srcref->sizrange[1]; | |
1071 | 1186 |
1072 bool strfunc_unknown_args = acs.dstsiz[0] == 0 && acs.dstsiz[1] != 0; | 1187 bool strfunc_unknown_args = acs.dstsiz[0] == 0 && acs.dstsiz[1] != 0; |
1073 | 1188 |
1074 /* The lower bound is zero when the size is unknown because then | 1189 /* The lower bound is zero when the size is unknown because then |
1075 overlap is not certain. */ | 1190 overlap is not certain. */ |
1076 acs.dstsiz[0] = strfunc_unknown_args ? 0 : 1; | 1191 acs.dstsiz[0] = strfunc_unknown_args ? 0 : 1; |
1077 acs.dstsiz[1] = 1; | 1192 acs.dstsiz[1] = 1; |
1078 | 1193 |
1079 offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; | 1194 offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; |
1080 gcc_assert (maxsize <= maxobjsize); | |
1081 | 1195 |
1082 /* For references to the same base object, determine if there's a pair | 1196 /* For references to the same base object, determine if there's a pair |
1083 of valid offsets into the two references such that access between | 1197 of valid offsets into the two references such that access between |
1084 them doesn't overlap. Adjust both upper bounds to be valid for | 1198 them doesn't overlap. Adjust both upper bounds to be valid for |
1085 the smaller size (i.e., at most MAXSIZE - SIZE). */ | 1199 the smaller size (i.e., at most MAXSIZE - SIZE). */ |
1143 the terminating NUL, regardless of offsets and sizes. When | 1257 the terminating NUL, regardless of offsets and sizes. When |
1144 overlap is only possible its range is [0, 1]. */ | 1258 overlap is only possible its range is [0, 1]. */ |
1145 acs.ovlsiz[0] = dstref->sizrange[0] == dstref->sizrange[1] ? 1 : 0; | 1259 acs.ovlsiz[0] = dstref->sizrange[0] == dstref->sizrange[1] ? 1 : 0; |
1146 acs.ovlsiz[1] = 1; | 1260 acs.ovlsiz[1] = 1; |
1147 | 1261 |
1148 offset_int endoff = dstref->offrange[0] + dstref->sizrange[0]; | 1262 offset_int endoff |
1263 = dstref->offrange[0] + (dstref->sizrange[0] - srcref->sizrange[0]); | |
1149 if (endoff <= srcref->offrange[0]) | 1264 if (endoff <= srcref->offrange[0]) |
1150 acs.ovloff[0] = wi::smin (maxobjsize, srcref->offrange[0]).to_shwi (); | 1265 acs.ovloff[0] = wi::smin (maxobjsize, srcref->offrange[0]).to_shwi (); |
1151 else | 1266 else |
1152 acs.ovloff[0] = wi::smin (maxobjsize, endoff).to_shwi (); | 1267 acs.ovloff[0] = wi::smin (maxobjsize, endoff).to_shwi (); |
1153 | 1268 |
1192 bool | 1307 bool |
1193 builtin_access::overlap () | 1308 builtin_access::overlap () |
1194 { | 1309 { |
1195 builtin_access &acs = *this; | 1310 builtin_access &acs = *this; |
1196 | 1311 |
1197 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 1312 const offset_int maxobjsize = dstref->maxobjsize; |
1198 | 1313 |
1199 acs.sizrange[0] = wi::smax (dstref->sizrange[0], | 1314 acs.sizrange[0] = wi::smax (dstref->sizrange[0], |
1200 srcref->sizrange[0]).to_shwi (); | 1315 srcref->sizrange[0]).to_shwi (); |
1201 acs.sizrange[1] = wi::smax (dstref->sizrange[1], | 1316 acs.sizrange[1] = wi::smax (dstref->sizrange[1], |
1202 srcref->sizrange[1]).to_shwi (); | 1317 srcref->sizrange[1]).to_shwi (); |
1214 | 1329 |
1215 /* If both base objects aren't known return the maximum possible | 1330 /* If both base objects aren't known return the maximum possible |
1216 offset that would make them not overlap. */ | 1331 offset that would make them not overlap. */ |
1217 if (!dstref->base || !srcref->base) | 1332 if (!dstref->base || !srcref->base) |
1218 return false; | 1333 return false; |
1219 | |
1220 /* Set the access offsets. */ | |
1221 acs.dstoff[0] = dstref->offrange[0]; | |
1222 acs.dstoff[1] = dstref->offrange[1]; | |
1223 | 1334 |
1224 /* If the base object is an array adjust the bounds of the offset | 1335 /* If the base object is an array adjust the bounds of the offset |
1225 to be non-negative and within the bounds of the array if possible. */ | 1336 to be non-negative and within the bounds of the array if possible. */ |
1226 if (dstref->base | 1337 if (dstref->base |
1227 && TREE_CODE (TREE_TYPE (dstref->base)) == ARRAY_TYPE) | 1338 && TREE_CODE (TREE_TYPE (dstref->base)) == ARRAY_TYPE) |
1325 static bool | 1436 static bool |
1326 maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs) | 1437 maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs) |
1327 { | 1438 { |
1328 if (!acs.overlap ()) | 1439 if (!acs.overlap ()) |
1329 return false; | 1440 return false; |
1441 | |
1442 if (gimple_no_warning_p (call)) | |
1443 return true; | |
1330 | 1444 |
1331 /* For convenience. */ | 1445 /* For convenience. */ |
1332 const builtin_memref &dstref = *acs.dstref; | 1446 const builtin_memref &dstref = *acs.dstref; |
1333 const builtin_memref &srcref = *acs.srcref; | 1447 const builtin_memref &srcref = *acs.srcref; |
1334 | 1448 |
1370 else | 1484 else |
1371 sprintf (offstr[2], | 1485 sprintf (offstr[2], |
1372 "[" HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC "]", | 1486 "[" HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC "]", |
1373 ovloff[0], ovloff[1]); | 1487 ovloff[0], ovloff[1]); |
1374 | 1488 |
1375 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | 1489 const offset_int maxobjsize = dstref.maxobjsize; |
1376 bool must_overlap = ovlsiz[0] > 0; | 1490 bool must_overlap = ovlsiz[0] > 0; |
1377 | 1491 |
1378 if (ovlsiz[1] == 0) | 1492 if (ovlsiz[1] == 0) |
1379 ovlsiz[1] = ovlsiz[0]; | 1493 ovlsiz[1] = ovlsiz[0]; |
1380 | 1494 |
1565 ovlsiz[1], offstr[2]); | 1679 ovlsiz[1], offstr[2]); |
1566 | 1680 |
1567 return true; | 1681 return true; |
1568 } | 1682 } |
1569 | 1683 |
1570 /* Validate REF offsets in an EXPRession passed as an argument to a CALL | 1684 /* Validate REF size and offsets in an expression passed as an argument |
1571 to a built-in function FUNC to make sure they are within the bounds | 1685 to a CALL to a built-in function FUNC to make sure they are within |
1572 of the referenced object if its size is known, or PTRDIFF_MAX otherwise. | 1686 the bounds of the referenced object if its size is known, or |
1573 Both initial values of the offsets and their final value computed by | 1687 PTRDIFF_MAX otherwise. DO_WARN is true when a diagnostic should |
1574 the function by incrementing the initial value by the size are | 1688 be issued, false otherwise. |
1689 Both initial values of the offsets and their final value computed | |
1690 by the function by incrementing the initial value by the size are | |
1575 validated. Return true if the offsets are not valid and a diagnostic | 1691 validated. Return true if the offsets are not valid and a diagnostic |
1576 has been issued. */ | 1692 has been issued, or would have been issued if DO_WARN had been true. */ |
1577 | 1693 |
1578 static bool | 1694 static bool |
1579 maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict, | 1695 maybe_diag_access_bounds (location_t loc, gimple *call, tree func, int strict, |
1580 tree expr, const builtin_memref &ref) | 1696 const builtin_memref &ref, offset_int wroff, |
1581 { | 1697 bool do_warn) |
1582 if (!warn_array_bounds) | 1698 { |
1583 return false; | 1699 const offset_int maxobjsize = ref.maxobjsize; |
1584 | 1700 |
1585 offset_int ooboff[] = { ref.offrange[0], ref.offrange[1] }; | 1701 /* Check for excessive size first and regardless of warning options |
1702 since the result is used to make codegen decisions. */ | |
1703 if (ref.sizrange[0] > maxobjsize) | |
1704 { | |
1705 /* Return true without issuing a warning. */ | |
1706 if (!do_warn) | |
1707 return true; | |
1708 | |
1709 if (ref.ref && TREE_NO_WARNING (ref.ref)) | |
1710 return false; | |
1711 | |
1712 if (warn_stringop_overflow) | |
1713 { | |
1714 if (EXPR_HAS_LOCATION (ref.ptr)) | |
1715 loc = EXPR_LOCATION (ref.ptr); | |
1716 | |
1717 loc = expansion_point_location_if_in_system_header (loc); | |
1718 | |
1719 if (ref.sizrange[0] == ref.sizrange[1]) | |
1720 return warning_at (loc, OPT_Wstringop_overflow_, | |
1721 "%G%qD specified bound %wu " | |
1722 "exceeds maximum object size %wu", | |
1723 call, func, ref.sizrange[0].to_uhwi (), | |
1724 maxobjsize.to_uhwi ()); | |
1725 | |
1726 return warning_at (loc, OPT_Wstringop_overflow_, | |
1727 "%G%qD specified bound between %wu and %wu " | |
1728 "exceeds maximum object size %wu", | |
1729 call, func, ref.sizrange[0].to_uhwi (), | |
1730 ref.sizrange[1].to_uhwi (), | |
1731 maxobjsize.to_uhwi ()); | |
1732 } | |
1733 } | |
1734 | |
1735 /* Check for out-bounds pointers regardless of warning options since | |
1736 the result is used to make codegen decisions. An excessive WROFF | |
1737 can only come up as a result of an invalid strncat bound and is | |
1738 diagnosed separately using a more meaningful warning. */ | |
1739 if (maxobjsize < wroff) | |
1740 wroff = 0; | |
1741 offset_int ooboff[] = { ref.offrange[0], ref.offrange[1], wroff }; | |
1586 tree oobref = ref.offset_out_of_bounds (strict, ooboff); | 1742 tree oobref = ref.offset_out_of_bounds (strict, ooboff); |
1587 if (!oobref) | 1743 if (!oobref) |
1588 return false; | 1744 return false; |
1589 | 1745 |
1590 if (EXPR_HAS_LOCATION (expr)) | 1746 /* Return true without issuing a warning. */ |
1591 loc = EXPR_LOCATION (expr); | 1747 if (!do_warn) |
1748 return true; | |
1749 | |
1750 if (!warn_array_bounds) | |
1751 return false; | |
1752 | |
1753 if (TREE_NO_WARNING (ref.ptr) | |
1754 || (ref.ref && TREE_NO_WARNING (ref.ref))) | |
1755 return false; | |
1756 | |
1757 if (EXPR_HAS_LOCATION (ref.ptr)) | |
1758 loc = EXPR_LOCATION (ref.ptr); | |
1592 | 1759 |
1593 loc = expansion_point_location_if_in_system_header (loc); | 1760 loc = expansion_point_location_if_in_system_header (loc); |
1594 | 1761 |
1595 char rangestr[2][64]; | 1762 char rangestr[2][64]; |
1596 if (ooboff[0] == ooboff[1] | 1763 if (ooboff[0] == ooboff[1] |
1605 bool warned = false; | 1772 bool warned = false; |
1606 | 1773 |
1607 if (oobref == error_mark_node) | 1774 if (oobref == error_mark_node) |
1608 { | 1775 { |
1609 if (ref.sizrange[0] == ref.sizrange[1]) | 1776 if (ref.sizrange[0] == ref.sizrange[1]) |
1610 sprintf (rangestr[1], "%lli", (long long) ref.sizrange[0].to_shwi ()); | 1777 sprintf (rangestr[1], "%llu", |
1778 (unsigned long long) ref.sizrange[0].to_shwi ()); | |
1611 else | 1779 else |
1612 sprintf (rangestr[1], "[%lli, %lli]", | 1780 sprintf (rangestr[1], "[%lli, %lli]", |
1613 (long long) ref.sizrange[0].to_shwi (), | 1781 (unsigned long long) ref.sizrange[0].to_uhwi (), |
1614 (long long) ref.sizrange[1].to_shwi ()); | 1782 (unsigned long long) ref.sizrange[1].to_uhwi ()); |
1615 | 1783 |
1616 tree type; | 1784 tree type; |
1617 | 1785 |
1618 if (DECL_P (ref.base) | 1786 if (DECL_P (ref.base) |
1619 && TREE_CODE (type = TREE_TYPE (ref.base)) == ARRAY_TYPE) | 1787 && TREE_CODE (type = TREE_TYPE (ref.base)) == ARRAY_TYPE) |
1640 "and size %s", | 1808 "and size %s", |
1641 call, func, rangestr[0], rangestr[1]); | 1809 call, func, rangestr[0], rangestr[1]); |
1642 } | 1810 } |
1643 else if (oobref == ref.base) | 1811 else if (oobref == ref.base) |
1644 { | 1812 { |
1645 const offset_int maxobjsize = tree_to_shwi (max_object_size ()); | |
1646 | |
1647 /* True when the offset formed by an access to the reference | 1813 /* True when the offset formed by an access to the reference |
1648 is out of bounds, rather than the initial offset wich is | 1814 is out of bounds, rather than the initial offset wich is |
1649 in bounds. This implies access past the end. */ | 1815 in bounds. This implies access past the end. */ |
1650 bool form = ooboff[0] != ref.offrange[0]; | 1816 bool form = ooboff[0] != ref.offrange[0]; |
1651 | 1817 |
1691 : G_("%G%qD offset %s is out of bounds"), | 1857 : G_("%G%qD offset %s is out of bounds"), |
1692 call, func, rangestr[0]); | 1858 call, func, rangestr[0]); |
1693 } | 1859 } |
1694 else if (TREE_CODE (ref.ref) == MEM_REF) | 1860 else if (TREE_CODE (ref.ref) == MEM_REF) |
1695 { | 1861 { |
1696 tree type = TREE_TYPE (TREE_OPERAND (ref.ref, 0)); | 1862 tree refop = TREE_OPERAND (ref.ref, 0); |
1863 tree type = TREE_TYPE (refop); | |
1697 if (POINTER_TYPE_P (type)) | 1864 if (POINTER_TYPE_P (type)) |
1698 type = TREE_TYPE (type); | 1865 type = TREE_TYPE (type); |
1699 type = TYPE_MAIN_VARIANT (type); | 1866 type = TYPE_MAIN_VARIANT (type); |
1700 | 1867 |
1701 warned = warning_at (loc, OPT_Warray_bounds, | 1868 if (warning_at (loc, OPT_Warray_bounds, |
1702 "%G%qD offset %s from the object at %qE is out " | 1869 "%G%qD offset %s from the object at %qE is out " |
1703 "of the bounds of %qT", | 1870 "of the bounds of %qT", |
1704 call, func, rangestr[0], ref.base, type); | 1871 call, func, rangestr[0], ref.base, type)) |
1872 { | |
1873 if (TREE_CODE (ref.ref) == COMPONENT_REF) | |
1874 refop = TREE_OPERAND (ref.ref, 1); | |
1875 if (DECL_P (refop)) | |
1876 inform (DECL_SOURCE_LOCATION (refop), | |
1877 "subobject %qD declared here", refop); | |
1878 warned = true; | |
1879 } | |
1705 } | 1880 } |
1706 else | 1881 else |
1707 { | 1882 { |
1883 tree refop = TREE_OPERAND (ref.ref, 0); | |
1708 tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref.ref)); | 1884 tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref.ref)); |
1709 | 1885 |
1710 warned = warning_at (loc, OPT_Warray_bounds, | 1886 if (warning_at (loc, OPT_Warray_bounds, |
1711 "%G%qD offset %s from the object at %qE is out " | 1887 "%G%qD offset %s from the object at %qE is out " |
1712 "of the bounds of referenced subobject %qD with " | 1888 "of the bounds of referenced subobject %qD with " |
1713 "type %qT at offset %wu", | 1889 "type %qT at offset %wi", |
1714 call, func, rangestr[0], ref.base, | 1890 call, func, rangestr[0], ref.base, |
1715 TREE_OPERAND (ref.ref, 1), type, | 1891 TREE_OPERAND (ref.ref, 1), type, |
1716 ref.refoff.to_uhwi ()); | 1892 ref.refoff.to_shwi ())) |
1893 { | |
1894 if (TREE_CODE (ref.ref) == COMPONENT_REF) | |
1895 refop = TREE_OPERAND (ref.ref, 1); | |
1896 if (DECL_P (refop)) | |
1897 inform (DECL_SOURCE_LOCATION (refop), | |
1898 "subobject %qD declared here", refop); | |
1899 warned = true; | |
1900 } | |
1717 } | 1901 } |
1718 | 1902 |
1719 return warned; | 1903 return warned; |
1720 } | 1904 } |
1721 | 1905 |
1764 dst_idx = 0; | 1948 dst_idx = 0; |
1765 src_idx = 1; | 1949 src_idx = 1; |
1766 bnd_idx = 2; | 1950 bnd_idx = 2; |
1767 break; | 1951 break; |
1768 | 1952 |
1953 case BUILT_IN_MEMSET: | |
1954 case BUILT_IN_MEMSET_CHK: | |
1955 dst_idx = 0; | |
1956 bnd_idx = 2; | |
1957 break; | |
1958 | |
1769 case BUILT_IN_STPCPY: | 1959 case BUILT_IN_STPCPY: |
1770 case BUILT_IN_STPCPY_CHK: | 1960 case BUILT_IN_STPCPY_CHK: |
1771 case BUILT_IN_STRCPY: | 1961 case BUILT_IN_STRCPY: |
1772 case BUILT_IN_STRCPY_CHK: | 1962 case BUILT_IN_STRCPY_CHK: |
1773 case BUILT_IN_STRCAT: | 1963 case BUILT_IN_STRCAT: |
1794 if (!dstwr && strfun) | 1984 if (!dstwr && strfun) |
1795 dstwr = size_one_node; | 1985 dstwr = size_one_node; |
1796 | 1986 |
1797 /* DST and SRC can be null for a call with an insufficient number | 1987 /* DST and SRC can be null for a call with an insufficient number |
1798 of arguments to a built-in function declared without a protype. */ | 1988 of arguments to a built-in function declared without a protype. */ |
1799 if (!dst || !src) | 1989 if (!dst || (src_idx < nargs && !src)) |
1800 return; | 1990 return; |
1801 | 1991 |
1802 /* DST, SRC, or DSTWR can also have the wrong type in a call to | 1992 /* DST, SRC, or DSTWR can also have the wrong type in a call to |
1803 a function declared without a prototype. Avoid checking such | 1993 a function declared without a prototype. Avoid checking such |
1804 invalid calls. */ | 1994 invalid calls. */ |
1805 if (TREE_CODE (TREE_TYPE (dst)) != POINTER_TYPE | 1995 if (TREE_CODE (TREE_TYPE (dst)) != POINTER_TYPE |
1806 || TREE_CODE (TREE_TYPE (src)) != POINTER_TYPE | 1996 || (src && TREE_CODE (TREE_TYPE (src)) != POINTER_TYPE) |
1807 || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr)))) | 1997 || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr)))) |
1808 return; | 1998 return; |
1809 | 1999 |
1810 if (check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE)) | 2000 if (!check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE)) |
1811 return; | 2001 return; |
1812 | 2002 |
1813 /* Avoid diagnosing the call again. */ | 2003 /* Avoid diagnosing the call again. */ |
1814 gimple_set_no_warning (call, true); | 2004 gimple_set_no_warning (call, true); |
1815 } | 2005 } |
1817 } /* anonymous namespace */ | 2007 } /* anonymous namespace */ |
1818 | 2008 |
1819 /* Attempt to detect and diagnose invalid offset bounds and (except for | 2009 /* Attempt to detect and diagnose invalid offset bounds and (except for |
1820 memmove) overlapping copy in a call expression EXPR from SRC to DST | 2010 memmove) overlapping copy in a call expression EXPR from SRC to DST |
1821 and DSTSIZE and SRCSIZE bytes, respectively. Both DSTSIZE and | 2011 and DSTSIZE and SRCSIZE bytes, respectively. Both DSTSIZE and |
1822 SRCSIZE may be NULL. Return false when one or the other has been | 2012 SRCSIZE may be NULL. DO_WARN is false to detect either problem |
1823 detected and diagnosed, true otherwise. */ | 2013 without issue a warning. Return the OPT_Wxxx constant corresponding |
1824 | 2014 to the warning if one has been detected and zero otherwise. */ |
1825 bool | 2015 |
2016 int | |
1826 check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize, | 2017 check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize, |
1827 tree srcsize, bool bounds_only /* = false */) | 2018 tree srcsize, bool bounds_only /* = false */, |
2019 bool do_warn /* = true */) | |
1828 { | 2020 { |
1829 location_t loc = gimple_nonartificial_location (call); | 2021 location_t loc = gimple_nonartificial_location (call); |
1830 loc = expansion_point_location_if_in_system_header (loc); | 2022 loc = expansion_point_location_if_in_system_header (loc); |
1831 | 2023 |
1832 tree func = gimple_call_fndecl (call); | 2024 tree func = gimple_call_fndecl (call); |
1833 | 2025 |
1834 builtin_memref dstref (dst, dstsize); | 2026 builtin_memref dstref (dst, dstsize); |
1835 builtin_memref srcref (src, srcsize); | 2027 builtin_memref srcref (src, srcsize); |
1836 | 2028 |
2029 /* Create a descriptor of the access. This may adjust both DSTREF | |
2030 and SRCREF based on one another and the kind of the access. */ | |
1837 builtin_access acs (call, dstref, srcref); | 2031 builtin_access acs (call, dstref, srcref); |
1838 | 2032 |
1839 /* Set STRICT to the value of the -Warray-bounds=N argument for | 2033 /* Set STRICT to the value of the -Warray-bounds=N argument for |
1840 string functions or when N > 1. */ | 2034 string functions or when N > 1. */ |
1841 int strict = (acs.strict () || warn_array_bounds > 1 ? warn_array_bounds : 0); | 2035 int strict = (acs.strict () || warn_array_bounds > 1 ? warn_array_bounds : 0); |
1842 | 2036 |
1843 /* Validate offsets first to make sure they are within the bounds | 2037 /* The starting offset of the destination write access. Nonzero only |
1844 of the destination object if its size is known, or PTRDIFF_MAX | 2038 for the strcat family of functions. */ |
1845 otherwise. */ | 2039 offset_int wroff = acs.write_off (dstsize); |
1846 if (maybe_diag_offset_bounds (loc, call, func, strict, dst, dstref) | 2040 |
1847 || maybe_diag_offset_bounds (loc, call, func, strict, src, srcref)) | 2041 /* Validate offsets to each reference before the access first to make |
1848 { | 2042 sure they are within the bounds of the destination object if its |
1849 gimple_set_no_warning (call, true); | 2043 size is known, or PTRDIFF_MAX otherwise. */ |
1850 return false; | 2044 if (maybe_diag_access_bounds (loc, call, func, strict, dstref, wroff, do_warn) |
1851 } | 2045 || maybe_diag_access_bounds (loc, call, func, strict, srcref, 0, do_warn)) |
1852 | 2046 { |
1853 bool check_overlap | 2047 if (do_warn) |
1854 = (warn_restrict | 2048 gimple_set_no_warning (call, true); |
1855 && (bounds_only | 2049 return OPT_Warray_bounds; |
1856 || (DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE | 2050 } |
1857 && DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE_CHK))); | 2051 |
1858 | 2052 if (!warn_restrict || bounds_only || !src) |
1859 if (!check_overlap) | 2053 return 0; |
1860 return true; | 2054 |
2055 if (!bounds_only) | |
2056 { | |
2057 switch (DECL_FUNCTION_CODE (func)) | |
2058 { | |
2059 case BUILT_IN_MEMMOVE: | |
2060 case BUILT_IN_MEMMOVE_CHK: | |
2061 case BUILT_IN_MEMSET: | |
2062 case BUILT_IN_MEMSET_CHK: | |
2063 return 0; | |
2064 default: | |
2065 break; | |
2066 } | |
2067 } | |
1861 | 2068 |
1862 if (operand_equal_p (dst, src, 0)) | 2069 if (operand_equal_p (dst, src, 0)) |
1863 { | 2070 { |
1864 /* Issue -Wrestrict unless the pointers are null (those do | 2071 /* Issue -Wrestrict unless the pointers are null (those do |
1865 not point to objects and so do not indicate an overlap; | 2072 not point to objects and so do not indicate an overlap; |
1869 { | 2076 { |
1870 warning_at (loc, OPT_Wrestrict, | 2077 warning_at (loc, OPT_Wrestrict, |
1871 "%G%qD source argument is the same as destination", | 2078 "%G%qD source argument is the same as destination", |
1872 call, func); | 2079 call, func); |
1873 gimple_set_no_warning (call, true); | 2080 gimple_set_no_warning (call, true); |
1874 return false; | 2081 return OPT_Wrestrict; |
1875 } | 2082 } |
1876 | 2083 |
1877 return true; | 2084 return 0; |
1878 } | 2085 } |
1879 | 2086 |
1880 /* Return false when overlap has been detected. */ | 2087 /* Return false when overlap has been detected. */ |
1881 if (maybe_diag_overlap (loc, call, acs)) | 2088 if (maybe_diag_overlap (loc, call, acs)) |
1882 { | 2089 { |
1883 gimple_set_no_warning (call, true); | 2090 gimple_set_no_warning (call, true); |
1884 return false; | 2091 return OPT_Wrestrict; |
1885 } | 2092 } |
1886 | 2093 |
1887 return true; | 2094 return 0; |
1888 } | 2095 } |
1889 | 2096 |
1890 gimple_opt_pass * | 2097 gimple_opt_pass * |
1891 make_pass_warn_restrict (gcc::context *ctxt) | 2098 make_pass_warn_restrict (gcc::context *ctxt) |
1892 { | 2099 { |
1893 return new pass_wrestrict (ctxt); | 2100 return new pass_wrestrict (ctxt); |
1894 } | 2101 } |
2102 | |
2103 DEBUG_FUNCTION void | |
2104 dump_builtin_memref (FILE *fp, const builtin_memref &ref) | |
2105 { | |
2106 fprintf (fp, "\n ptr = "); | |
2107 print_generic_expr (fp, ref.ptr, TDF_LINENO); | |
2108 fprintf (fp, "\n ref = "); | |
2109 if (ref.ref) | |
2110 print_generic_expr (fp, ref.ref, TDF_LINENO); | |
2111 else | |
2112 fputs ("null", fp); | |
2113 fprintf (fp, "\n base = "); | |
2114 print_generic_expr (fp, ref.base, TDF_LINENO); | |
2115 fprintf (fp, | |
2116 "\n basesize = %lli" | |
2117 "\n refsize = %lli" | |
2118 "\n refoff = %lli" | |
2119 "\n offrange = [%lli, %lli]" | |
2120 "\n sizrange = [%lli, %lli]" | |
2121 "\n strbounded_p = %s\n", | |
2122 (long long)ref.basesize.to_shwi (), | |
2123 (long long)ref.refsize.to_shwi (), | |
2124 (long long)ref.refoff.to_shwi (), | |
2125 (long long)ref.offrange[0].to_shwi (), | |
2126 (long long)ref.offrange[1].to_shwi (), | |
2127 (long long)ref.sizrange[0].to_shwi (), | |
2128 (long long)ref.sizrange[1].to_shwi (), | |
2129 ref.strbounded_p ? "true" : "false"); | |
2130 } | |
2131 | |
2132 void | |
2133 builtin_access::dump (FILE *fp) const | |
2134 { | |
2135 fprintf (fp, " dstref:"); | |
2136 dump_builtin_memref (fp, *dstref); | |
2137 fprintf (fp, "\n srcref:"); | |
2138 dump_builtin_memref (fp, *srcref); | |
2139 | |
2140 fprintf (fp, | |
2141 " sizrange = [%lli, %lli]\n" | |
2142 " ovloff = [%lli, %lli]\n" | |
2143 " ovlsiz = [%lli, %lli]\n" | |
2144 " dstoff = [%lli, %lli]\n" | |
2145 " dstsiz = [%lli, %lli]\n" | |
2146 " srcoff = [%lli, %lli]\n" | |
2147 " srcsiz = [%lli, %lli]\n", | |
2148 (long long)sizrange[0], (long long)sizrange[1], | |
2149 (long long)ovloff[0], (long long)ovloff[1], | |
2150 (long long)ovlsiz[0], (long long)ovlsiz[1], | |
2151 (long long)dstoff[0].to_shwi (), (long long)dstoff[1].to_shwi (), | |
2152 (long long)dstsiz[0].to_shwi (), (long long)dstsiz[1].to_shwi (), | |
2153 (long long)srcoff[0].to_shwi (), (long long)srcoff[1].to_shwi (), | |
2154 (long long)srcsiz[0].to_shwi (), (long long)srcsiz[1].to_shwi ()); | |
2155 } | |
2156 | |
2157 DEBUG_FUNCTION void | |
2158 dump_builtin_access (FILE *fp, gimple *stmt, const builtin_access &acs) | |
2159 { | |
2160 if (stmt) | |
2161 { | |
2162 fprintf (fp, "\nDumping builtin_access for "); | |
2163 print_gimple_expr (fp, stmt, TDF_LINENO); | |
2164 fputs (":\n", fp); | |
2165 } | |
2166 | |
2167 acs.dump (fp); | |
2168 } | |
2169 | |
2170 DEBUG_FUNCTION void | |
2171 debug (gimple *stmt, const builtin_access &acs) | |
2172 { | |
2173 dump_builtin_access (stdout, stmt, acs); | |
2174 } |