diff options
author | Qing Zhao <qing.zhao@oracle.com> | 2022-12-06 18:50:04 +0000 |
---|---|---|
committer | Qing Zhao <qing.zhao@oracle.com> | 2022-12-06 18:50:04 +0000 |
commit | 710c9676520dfd38b4bfdcc937ce026ed89921d6 (patch) | |
tree | 81a6bc70c710cba93ab79a61180ce822fe31ae13 /gcc/tree.cc | |
parent | dcfc7ac94dbcf6c86c0c58ce6dc1d8bd853e4093 (diff) | |
download | gcc-710c9676520dfd38b4bfdcc937ce026ed89921d6.zip gcc-710c9676520dfd38b4bfdcc937ce026ed89921d6.tar.gz gcc-710c9676520dfd38b4bfdcc937ce026ed89921d6.tar.bz2 |
Update -Warray-bounds with -fstrict-flex-arrays.
A. add the following to clarify the relationship between -Warray-bounds
and the LEVEL of -fstrict-flex-array:
By default, the trailing array of a structure will be treated as a
flexible array member by '-Warray-bounds' or '-Warray-bounds=N' if
it is declared as either a flexible array member per C99 standard
onwards ('[]'), a GCC zero-length array extension ('[0]'), or an
one-element array ('[1]'). As a result, out of bounds subscripts
or offsets into zero-length arrays or one-element arrays are not
warned by default.
You can add the option '-fstrict-flex-arrays' or
'-fstrict-flex-arrays=LEVEL' to control how this option treat
trailing array of a structure as a flexible array member.
when LEVEL<=1, no change to the default behavior.
when LEVEL=2, additional warnings will be issued for out of bounds
subscripts or offsets into one-element arrays;
when LEVEL=3, in addition to LEVEL=2, additional warnings will be
issued for out of bounds subscripts or offsets into zero-length
arrays.
B. change -Warray-bounds=2 to exclude its control on how to treat
trailing arrays as flexible array members:
'-Warray-bounds=2'
This warning level also warns about the intermediate results
of pointer arithmetic that may yield out of bounds values.
This warning level may give a larger number of false positives
and is deactivated by default.
gcc/ChangeLog:
* attribs.cc (strict_flex_array_level_of): New function.
* attribs.h (strict_flex_array_level_of): Prototype for new function.
* doc/invoke.texi: Update -Warray-bounds by specifying the impact from
-fstrict-flex-arrays. Also update -Warray-bounds=2 by eliminating its
impact on treating trailing arrays as flexible array members.
* gimple-array-bounds.cc (get_up_bounds_for_array_ref): New function.
(check_out_of_bounds_and_warn): New function.
(array_bounds_checker::check_array_ref): Update with call to the above
new functions.
* tree.cc (array_ref_flexible_size_p): Add one new argument.
(component_ref_sam_type): New function.
(component_ref_size): Control with level of strict-flex-array.
* tree.h (array_ref_flexible_size_p): Update prototype.
(enum struct special_array_member): Add two new enum values.
(component_ref_sam_type): New prototype.
gcc/c/ChangeLog:
* c-decl.cc (is_flexible_array_member_p): Call new function
strict_flex_array_level_of.
gcc/testsuite/ChangeLog:
* gcc.dg/Warray-bounds-11.c: Update warnings for -Warray-bounds=2.
* gcc.dg/Warray-bounds-flex-arrays-1.c: New test.
* gcc.dg/Warray-bounds-flex-arrays-2.c: New test.
* gcc.dg/Warray-bounds-flex-arrays-3.c: New test.
* gcc.dg/Warray-bounds-flex-arrays-4.c: New test.
* gcc.dg/Warray-bounds-flex-arrays-5.c: New test.
* gcc.dg/Warray-bounds-flex-arrays-6.c: New test.
Diffstat (limited to 'gcc/tree.cc')
-rw-r--r-- | gcc/tree.cc | 159 |
1 files changed, 118 insertions, 41 deletions
diff --git a/gcc/tree.cc b/gcc/tree.cc index 254b237..b40c95a 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -12719,15 +12719,21 @@ array_ref_up_bound (tree exp) int test (uint8_t *p, uint32_t t[1][1], int n) { for (int i = 0; i < 4; i++, p++) t[i][0] = ...; + + If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A. */ bool -array_ref_flexible_size_p (tree ref) +array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */) { - /* the TYPE for this array referece. */ + /* The TYPE for this array referece. */ tree atype = NULL_TREE; - /* the FIELD_DECL for the array field in the containing structure. */ + /* The FIELD_DECL for the array field in the containing structure. */ tree afield_decl = NULL_TREE; + /* Whether this array is the trailing array of a structure. */ + bool is_trailing_array_tmp = false; + if (!is_trailing_array) + is_trailing_array = &is_trailing_array_tmp; if (TREE_CODE (ref) == ARRAY_REF || TREE_CODE (ref) == ARRAY_RANGE_REF) @@ -12815,7 +12821,10 @@ array_ref_flexible_size_p (tree ref) if (! TYPE_SIZE (atype) || ! TYPE_DOMAIN (atype) || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + { + *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + } /* If the reference is based on a declared entity, the size of the array is constrained by its given domain. (Do not trust commons PR/69368). */ @@ -12837,9 +12846,17 @@ array_ref_flexible_size_p (tree ref) if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST) - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + { + *is_trailing_array + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + } if (! get_addr_base_and_unit_offset (ref_to_array, &offset)) - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + { + *is_trailing_array + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + } /* If at least one extra element fits it is a flexarray. */ if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) @@ -12847,11 +12864,16 @@ array_ref_flexible_size_p (tree ref) + 2) * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))), wi::to_offset (DECL_SIZE_UNIT (ref)) - offset)) - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + { + *is_trailing_array + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; + } return false; } + *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL; return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; } @@ -12913,11 +12935,63 @@ get_initializer_for (tree init, tree decl) return NULL_TREE; } +/* Determines the special array member type for the array reference REF. */ +special_array_member +component_ref_sam_type (tree ref) +{ + special_array_member sam_type = special_array_member::none; + + tree member = TREE_OPERAND (ref, 1); + tree memsize = DECL_SIZE_UNIT (member); + if (memsize) + { + tree memtype = TREE_TYPE (member); + if (TREE_CODE (memtype) != ARRAY_TYPE) + return sam_type; + + bool trailing = false; + (void)array_ref_flexible_size_p (ref, &trailing); + bool zero_length = integer_zerop (memsize); + if (!trailing && !zero_length) + /* MEMBER is an interior array with + more than one element. */ + return special_array_member::int_n; + + if (zero_length) + { + if (trailing) + return special_array_member::trail_0; + else + return special_array_member::int_0; + } + + if (!zero_length) + 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); + offset_int neltsm1 = maxidx - minidx; + if (neltsm1 > 0) + /* MEMBER is a trailing array with more than + one elements. */ + return special_array_member::trail_n; + + if (neltsm1 == 0) + return special_array_member::trail_1; + } + } + + return sam_type; +} + /* 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. - If non-null, set *ARK when REF refers to an interior zero-length - array or a trailing one-element array. + If non-null, set *SAM to the type of special array member. Returns the size as sizetype (which might be zero for an object with an uninitialized flexible array member) or null if the size cannot be determined. */ @@ -12930,7 +13004,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */) special_array_member sambuf; if (!sam) sam = &sambuf; - *sam = special_array_member::none; + *sam = component_ref_sam_type (ref); /* The object/argument referenced by the COMPONENT_REF and its type. */ tree arg = TREE_OPERAND (ref, 0); @@ -12951,43 +13025,46 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */) return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype)) ? memsize : NULL_TREE); - bool trailing = array_ref_flexible_size_p (ref); - bool zero_length = integer_zerop (memsize); - if (!trailing && !zero_length) - /* MEMBER is either an interior array or is an array with - more than one element. */ + /* 2-or-more elements arrays are treated as normal arrays by default. */ + if (*sam == special_array_member::int_n + || *sam == special_array_member::trail_n) return memsize; - if (zero_length) + /* flag_strict_flex_arrays will control how to treat + the trailing arrays as flexiable array members. */ + + tree afield_decl = TREE_OPERAND (ref, 1); + unsigned int strict_flex_array_level + = strict_flex_array_level_of (afield_decl); + + switch (strict_flex_array_level) { - if (trailing) - *sam = special_array_member::trail_0; - else - { - *sam = special_array_member::int_0; - memsize = NULL_TREE; - } + case 3: + /* Treaing 0-length trailing arrays as normal array. */ + if (*sam == special_array_member::trail_0) + return size_zero_node; + /* FALLTHROUGH. */ + case 2: + /* Treating 1-element trailing arrays as normal array. */ + if (*sam == special_array_member::trail_1) + return memsize; + /* FALLTHROUGH. */ + case 1: + /* Treating 2-or-more elements trailing arrays as normal + array. */ + if (*sam == special_array_member::trail_n) + return memsize; + /* FALLTHROUGH. */ + case 0: + break; + default: + gcc_unreachable (); } - if (!zero_length) - 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); - offset_int neltsm1 = maxidx - minidx; - if (neltsm1 > 0) - /* MEMBER is an array with more than one element. */ - return memsize; - - if (neltsm1 == 0) - *sam = special_array_member::trail_1; - } + if (*sam == special_array_member::int_0) + memsize = NULL_TREE; - /* For a reference to a zero- or one-element array member of a union + /* For a reference to a flexible array member of a union use the size of the union instead of the size of the member. */ if (TREE_CODE (argtype) == UNION_TYPE) memsize = TYPE_SIZE_UNIT (argtype); |