aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2019-09-19 22:15:34 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2019-09-19 16:15:34 -0600
commit6889a3acfeed47265886676c6d43b04ef799fb82 (patch)
tree8101bfd6fc153a6707fc453e76507f09e0916c46 /gcc/tree.c
parent7d112d6670a0e0e662f8a7e64c33686e475832c8 (diff)
downloadgcc-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.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index 6be756c..59ea6b9 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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. */