aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-object-size.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2020-05-18 15:24:12 -0600
committerMartin Sebor <msebor@redhat.com>2020-05-18 15:24:12 -0600
commit7a41fcde6c67faafab8c8ee2a31140999383dcef (patch)
tree05c39a4f7d249ebd4878d1b392aa0ba747a96a85 /gcc/tree-object-size.c
parent3956244c58acceebf1ef2cf9a63e99f0f82abcb7 (diff)
downloadgcc-7a41fcde6c67faafab8c8ee2a31140999383dcef.zip
gcc-7a41fcde6c67faafab8c8ee2a31140999383dcef.tar.gz
gcc-7a41fcde6c67faafab8c8ee2a31140999383dcef.tar.bz2
PR middle-end/92815 - spurious -Wstringop-overflow writing into a flexible array of an extern struct
gcc/ChangeLog: PR middle-end/92815 * tree-object-size.c (decl_init_size): New function. (addr_object_size): Call it. * tree.h (last_field): Declare. (first_field): Add attribute nonnull. gcc/testsuite/ChangeLog: PR middle-end/92815 * gcc.dg/Warray-bounds-56.c: Remove xfails. * gcc.dg/builtin-object-size-20.c: New test. * gcc.dg/builtin-object-size-21.c: New test.
Diffstat (limited to 'gcc/tree-object-size.c')
-rw-r--r--gcc/tree-object-size.c66
1 files changed, 53 insertions, 13 deletions
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 255ea63..8855065 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -166,6 +166,42 @@ compute_object_offset (const_tree expr, const_tree var)
return size_binop (code, base, off);
}
+/* Returns the size of the object designated by DECL considering its
+ initializer if it either has one or if it would not affect its size,
+ otherwise the size of the object without the initializer when MIN
+ is true, else null. An object's initializer affects the object's
+ size if it's a struct type with a flexible array member. */
+
+static tree
+decl_init_size (tree decl, bool min)
+{
+ tree size = DECL_SIZE_UNIT (decl);
+ tree type = TREE_TYPE (decl);
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return size;
+
+ tree last = last_field (type);
+ if (!last)
+ return size;
+
+ tree last_type = TREE_TYPE (last);
+ if (TREE_CODE (last_type) != ARRAY_TYPE
+ || TYPE_SIZE (last_type))
+ return size;
+
+ /* Use TYPE_SIZE_UNIT; DECL_SIZE_UNIT sometimes reflects the size
+ of the initializer and sometimes doesn't. */
+ size = TYPE_SIZE_UNIT (type);
+ tree ref = build3 (COMPONENT_REF, type, decl, last, NULL_TREE);
+ tree compsize = component_ref_size (ref);
+ if (!compsize)
+ return min ? size : NULL_TREE;
+
+ /* The size includes tail padding and initializer elements. */
+ tree pos = byte_position (last);
+ size = fold_build2 (PLUS_EXPR, TREE_TYPE (size), pos, compsize);
+ return size;
+}
/* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
@@ -194,8 +230,10 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
while (handled_component_p (pt_var))
pt_var = TREE_OPERAND (pt_var, 0);
- if (pt_var
- && TREE_CODE (pt_var) == MEM_REF)
+ if (!pt_var)
+ return false;
+
+ if (TREE_CODE (pt_var) == MEM_REF)
{
unsigned HOST_WIDE_INT sz;
@@ -236,24 +274,26 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
if (sz != unknown[object_size_type] && sz < offset_limit)
pt_var_size = size_int (sz);
}
- else if (pt_var
- && DECL_P (pt_var)
- && tree_fits_uhwi_p (DECL_SIZE_UNIT (pt_var))
- && tree_to_uhwi (DECL_SIZE_UNIT (pt_var)) < offset_limit)
+ else if (DECL_P (pt_var))
{
*pdecl = pt_var;
- pt_var_size = DECL_SIZE_UNIT (pt_var);
+ pt_var_size = decl_init_size (pt_var, object_size_type & 2);
+ if (!pt_var_size)
+ return false;
}
- else if (pt_var
- && TREE_CODE (pt_var) == STRING_CST
- && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
- && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
- && tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
- < offset_limit)
+ else if (TREE_CODE (pt_var) == STRING_CST)
pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
else
return false;
+ if (pt_var_size)
+ {
+ /* Validate the size determined above. */
+ if (!tree_fits_uhwi_p (pt_var_size)
+ || tree_to_uhwi (pt_var_size) >= offset_limit)
+ return false;
+ }
+
if (pt_var != TREE_OPERAND (ptr, 0))
{
tree var;