aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2020-10-09 14:48:43 -0600
committerMartin Sebor <msebor@redhat.com>2020-10-12 09:05:55 -0600
commit83685efd5fd1623cfc4e4c435ce2773d95d458d1 (patch)
tree5a6514717cd82b39bcec8872ba61871599c5684a /gcc/calls.c
parentde05c19d5fd661ae16dd75a895b49d32d12f5edc (diff)
downloadgcc-83685efd5fd1623cfc4e4c435ce2773d95d458d1.zip
gcc-83685efd5fd1623cfc4e4c435ce2773d95d458d1.tar.gz
gcc-83685efd5fd1623cfc4e4c435ce2773d95d458d1.tar.bz2
Generalize compute_objsize to return maximum size/offset instead of failing (PR middle-end/97023).
Also resolves: PR middle-end/97342 - bogus -Wstringop-overflow with nonzero signed and unsigned offsets PR middle-end/97023 - missing warning on buffer overflow in chained mempcpy PR middle-end/96384 - bogus -Wstringop-overflow= storing into multidimensional array with index in range gcc/ChangeLog: PR middle-end/97342 PR middle-end/97023 PR middle-end/96384 * builtins.c (access_ref::access_ref): Initialize new member. Use new enum. (access_ref::size_remaining): Define new member function. (inform_access): Handle expressions referencing objects. (gimple_call_alloc_size): Call get_size_range instead of get_range. (gimple_call_return_array): New function. (get_range): Rename... (get_offset_range): ...to this. Improve detection of ranges from types of expressions. (gimple_call_return_array): Adjust calls to get_range per above. (compute_objsize): Same. Set maximum size or offset instead of failing for unknown objects and handle more kinds of expressions. (compute_objsize): Call access_ref::size_remaining. (compute_objsize): Have transitional wrapper fail for pointers into unknown objects. (expand_builtin_strncmp): Call access_ref::size_remaining and handle new cases. * builtins.h (access_ref::size_remaining): Declare new member function. (access_ref::set_max_size_range): Define new member function. (access_ref::add_ofset, access_ref::add_max_ofset): Same. (access_ref::add_base0): New data member. * calls.c (get_size_range): Change argument type. Handle new condition. * calls.h (get_size_range): Adjust signature. (enum size_range_flags): Define new type. * gimple-ssa-warn-restrict.c (builtin_memref::builtin_memref): Correct argument to get_size_range. * tree-ssa-strlen.c (get_range): Handle anti-ranges. (maybe_warn_overflow): Check DECL_P before assuming it's one. gcc/testsuite/ChangeLog: PR middle-end/97342 PR middle-end/97023 PR middle-end/96384 * c-c++-common/Wrestrict.c: Adjust comment. * gcc.dg/Wstringop-overflow-34.c: Remove xfail. * gcc.dg/Wstringop-overflow-43.c: Remove xfails. Adjust regex patterns. * gcc.dg/pr51683.c: Prune out expected warning. * gcc.target/i386/pr60693.c: Same. * g++.dg/warn/Wplacement-new-size-8.C: New test. * gcc.dg/Wstringop-overflow-41.c: New test. * gcc.dg/Wstringop-overflow-44.s: New test. * gcc.dg/Wstringop-overflow-45.c: New test. * gcc.dg/Wstringop-overflow-46.c: New test. * gcc.dg/Wstringop-overflow-47.c: New test. * gcc.dg/Wstringop-overflow-49.c: New test. * gcc.dg/Wstringop-overflow-50.c: New test. * gcc.dg/Wstringop-overflow-51.c: New test. * gcc.dg/Wstringop-overflow-52.c: New test. * gcc.dg/Wstringop-overflow-53.c: New test. * gcc.dg/Wstringop-overflow-54.c: New test. * gcc.dg/Wstringop-overflow-55.c: New test. * gcc.dg/Wstringop-overread-5.c: New test.
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c69
1 files changed, 48 insertions, 21 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index 93da3d6..d3120b2 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1235,14 +1235,16 @@ alloc_max_size (void)
after adjusting it if necessary to make EXP a represents a valid size
of object, or a valid size argument to an allocation function declared
with attribute alloc_size (whose argument may be signed), or to a string
- manipulation function like memset. When ALLOW_ZERO is true, allow
- returning a range of [0, 0] for a size in an anti-range [1, N] where
- N > PTRDIFF_MAX. A zero range is a (nearly) invalid argument to
- allocation functions like malloc but it is a valid argument to
- functions like memset. */
+ manipulation function like memset.
+ When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for
+ a size in an anti-range [1, N] where N > PTRDIFF_MAX. A zero range is
+ a (nearly) invalid argument to allocation functions like malloc but it
+ is a valid argument to functions like memset.
+ When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange
+ in a multi-range, otherwise to the smallest valid subrange. */
bool
-get_size_range (tree exp, tree range[2], bool allow_zero /* = false */)
+get_size_range (tree exp, tree range[2], int flags /* = 0 */)
{
if (!exp)
return false;
@@ -1314,25 +1316,50 @@ get_size_range (tree exp, tree range[2], bool allow_zero /* = false */)
min = wi::zero (expprec);
}
}
- else if (wi::eq_p (0, min - 1))
+ else
{
- /* EXP is unsigned and not in the range [1, MAX]. That means
- it's either zero or greater than MAX. Even though 0 would
- normally be detected by -Walloc-zero, unless ALLOW_ZERO
- is true, set the range to [MAX, TYPE_MAX] so that when MAX
- is greater than the limit the whole range is diagnosed. */
- if (allow_zero)
- min = max = wi::zero (expprec);
- else
+ wide_int maxsize = wi::to_wide (max_object_size ());
+ min = wide_int::from (min, maxsize.get_precision (), UNSIGNED);
+ max = wide_int::from (max, maxsize.get_precision (), UNSIGNED);
+ if (wi::eq_p (0, min - 1))
{
+ /* EXP is unsigned and not in the range [1, MAX]. That means
+ it's either zero or greater than MAX. Even though 0 would
+ normally be detected by -Walloc-zero, unless ALLOW_ZERO
+ is set, set the range to [MAX, TYPE_MAX] so that when MAX
+ is greater than the limit the whole range is diagnosed. */
+ wide_int maxsize = wi::to_wide (max_object_size ());
+ if (flags & SR_ALLOW_ZERO)
+ {
+ if (wi::leu_p (maxsize, max + 1)
+ || !(flags & SR_USE_LARGEST))
+ min = max = wi::zero (expprec);
+ else
+ {
+ min = max + 1;
+ max = wi::to_wide (TYPE_MAX_VALUE (exptype));
+ }
+ }
+ else
+ {
+ min = max + 1;
+ max = wi::to_wide (TYPE_MAX_VALUE (exptype));
+ }
+ }
+ else if ((flags & SR_USE_LARGEST)
+ && wi::ltu_p (max + 1, maxsize))
+ {
+ /* When USE_LARGEST is set and the larger of the two subranges
+ is a valid size, use it... */
min = max + 1;
- max = wi::to_wide (TYPE_MAX_VALUE (exptype));
+ max = maxsize;
+ }
+ else
+ {
+ /* ...otherwise use the smaller subrange. */
+ max = min - 1;
+ min = wi::zero (expprec);
}
- }
- else
- {
- max = min - 1;
- min = wi::zero (expprec);
}
}