diff options
author | Martin Sebor <msebor@redhat.com> | 2019-09-19 22:15:34 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2019-09-19 16:15:34 -0600 |
commit | 6889a3acfeed47265886676c6d43b04ef799fb82 (patch) | |
tree | 8101bfd6fc153a6707fc453e76507f09e0916c46 /gcc/tree.c | |
parent | 7d112d6670a0e0e662f8a7e64c33686e475832c8 (diff) | |
download | gcc-6889a3acfeed47265886676c6d43b04ef799fb82.zip gcc-6889a3acfeed47265886676c6d43b04ef799fb82.tar.gz gcc-6889a3acfeed47265886676c6d43b04ef799fb82.tar.bz2 |
PR middle-end/91631 - buffer overflow into an array member of a declared object not detected
gcc/ChangeLog:
PR middle-end/91631
* builtins.c (component_size): Correct trailing array computation,
rename to component_ref_size and move...
(compute_objsize): Adjust.
* gimple-ssa-warn-restrict.c (builtin_memref::refsize): New member.
(builtin_access::strict): Do not consider mememmove.
(builtin_access::write_off): New function.
(builtin_memref::builtin_memref): Initialize refsize.
(builtin_memref::set_base_and_offset): Adjust refoff and compute
refsize.
(builtin_memref::offset_out_of_bounds): Use ooboff input values.
Handle refsize.
(builtin_access::builtin_access): Intialize dstoff to destination
refeence offset here instead of in maybe_diag_overlap. Adjust
referencess even to unrelated objects. Adjust sizrange of bounded
string functions to reflect bound. For strcat, adjust destination
sizrange by that of source.
(builtin_access::strcat_overlap): Adjust offsets and sizes
to reflect the increase in destination sizrange above.
(builtin_access::overlap): Do not set dstoff here but instead
in builtin_access::builtin_access.
(check_bounds_or_overlap): Use builtin_access::write_off.
(maybe_diag_access_bounds): Add argument. Add informational notes.
(dump_builtin_memref, dump_builtin_access): New functions.
* tree.c (component_ref_size): ...to here.
* tree.h (component_ref_size): Declare.
* tree-ssa-strlen (handle_builtin_strcat): Include the terminating
nul in the size of the source string.
gcc/testsuite/ChangeLog:
PR middle-end/91631
* /c-c++-common/Warray-bounds-3.c: Correct expected offsets.
* /c-c++-common/Warray-bounds-4.c: Same.
* gcc.dg/Warray-bounds-39.c: Remove xfails.
* gcc.dg/Warray-bounds-45.c: New test.
* gcc.dg/Warray-bounds-46.c: New test.
From-SVN: r275981
Diffstat (limited to 'gcc/tree.c')
-rw-r--r-- | gcc/tree.c | 70 |
1 files changed, 70 insertions, 0 deletions
@@ -67,6 +67,7 @@ along with GCC; see the file COPYING3. If not see #include "rtl.h" #include "regs.h" #include "tree-vector-builder.h" +#include "gimple-fold.h" /* Tree code classes. */ @@ -13850,6 +13851,75 @@ component_ref_field_offset (tree exp) return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp); } +/* Determines the size of the member referenced by the COMPONENT_REF + REF, using its initializer expression if necessary in order to + determine the size of an initialized flexible array member. + Returns the size (which might be zero for an object with + an uninitialized flexible array member) or null if the size + cannot be determined. */ + +tree +component_ref_size (tree ref) +{ + gcc_assert (TREE_CODE (ref) == COMPONENT_REF); + + tree member = TREE_OPERAND (ref, 1); + + /* If the member is not an array, or is not last, or is an array with + more than one element, return its size. Otherwise it's either + a bona fide flexible array member, or a zero-length array member, + or an array of length one treated as such. */ + tree size = DECL_SIZE_UNIT (member); + if (size) + { + tree memtype = TREE_TYPE (member); + if (TREE_CODE (memtype) != ARRAY_TYPE + || !array_at_struct_end_p (ref)) + return size; + + if (!integer_zerop (size)) + if (tree dom = TYPE_DOMAIN (memtype)) + if (tree min = TYPE_MIN_VALUE (dom)) + if (tree max = TYPE_MAX_VALUE (dom)) + if (TREE_CODE (min) == INTEGER_CST + && TREE_CODE (max) == INTEGER_CST) + { + offset_int minidx = wi::to_offset (min); + offset_int maxidx = wi::to_offset (max); + if (maxidx - minidx > 1) + return size; + } + } + + /* If the reference is to a declared object and the member a true + flexible array, try to determine its size from its initializer. */ + poly_int64 off = 0; + tree base = get_addr_base_and_unit_offset (ref, &off); + if (!base || !VAR_P (base)) + return NULL_TREE; + + /* The size of any member of a declared object other than a flexible + array member is that obtained above. */ + if (size) + return size; + + if (tree init = DECL_INITIAL (base)) + if (TREE_CODE (init) == CONSTRUCTOR) + { + off <<= LOG2_BITS_PER_UNIT; + init = fold_ctor_reference (NULL_TREE, init, off, 0, base); + if (init) + return TYPE_SIZE_UNIT (TREE_TYPE (init)); + } + + /* Return "don't know" for an external non-array object since its + flexible array member can be initialized to have any number of + elements. Otherwise, return zero because the flexible array + member has no elements. */ + return (DECL_EXTERNAL (base) && TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE + ? NULL_TREE : integer_zero_node); +} + /* Return the machine mode of T. For vectors, returns the mode of the inner type. The main use case is to feed the result to HONOR_NANS, avoiding the BLKmode that a direct TYPE_MODE (T) might return. */ |