From: Martin Sebor Date: Wed, 25 Jul 2018 02:11:31 +0000 (+0000) Subject: PR tree-optimization/86622 - incorrect strlen of array of array plus variable offset X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bfb9bd47b2daac0a01c561effac1d8244ddd99f6;p=gcc.git PR tree-optimization/86622 - incorrect strlen of array of array plus variable offset PR tree-optimization/86622 - incorrect strlen of array of array plus variable offset PR tree-optimization/86532 - Wrong code due to a wrong strlen folding starting with r262522 gcc/ChangeLog: PR tree-optimization/86622 PR tree-optimization/86532 * builtins.h (string_length): Declare. * builtins.c (c_strlen): Correct handling of non-constant offsets. (check_access): Be prepared for non-constant length ranges. (string_length): Make extern. * expr.c (string_constant): Only handle the minor non-constant array index. Use string_constant to compute the length of a generic string constant. gcc/testsuite/ChangeLog: PR tree-optimization/86622 PR tree-optimization/86532 * gcc.c-torture/execute/strlen-2.c: New test. * gcc.c-torture/execute/strlen-3.c: New test. * gcc.c-torture/execute/strlen-4.c: New test. From-SVN: r262958 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 96c7de91950..ee4b21254dd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2018-07-24 Martin Sebor + + PR tree-optimization/86622 + PR tree-optimization/86532 + * builtins.h (string_length): Declare. + * builtins.c (c_strlen): Correct handling of non-constant offsets. + (check_access): Be prepared for non-constant length ranges. + (string_length): Make extern. + * expr.c (string_constant): Only handle the minor non-constant + array index. Use string_constant to compute the length of + a generic string constant. + 2018-07-24 Richard Sandiford PR tree-optimization/86618 diff --git a/gcc/builtins.c b/gcc/builtins.c index 539a6d17688..aa3e0d80cd1 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -517,11 +517,11 @@ get_pointer_alignment (tree exp) return align; } -/* Return the number of non-zero elements in the sequence +/* Return the number of leading non-zero elements in the sequence [ PTR, PTR + MAXELTS ) where each element's size is ELTSIZE bytes. ELTSIZE must be a power of 2 less than 8. Used by c_strlen. */ -static unsigned +unsigned string_length (const void *ptr, unsigned eltsize, unsigned maxelts) { gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4); @@ -605,14 +605,21 @@ c_strlen (tree src, int only_value) /* Set MAXELTS to sizeof (SRC) / sizeof (*SRC) - 1, the maximum possible length of SRC. Prefer TYPE_SIZE() to TREE_STRING_LENGTH() if possible - in case the latter is less than the size of the array. */ - HOST_WIDE_INT maxelts = TREE_STRING_LENGTH (src); + in case the latter is less than the size of the array, such as when + SRC refers to a short string literal used to initialize a large array. + In that case, the elements of the array after the terminating NUL are + all NUL. */ + HOST_WIDE_INT strelts = TREE_STRING_LENGTH (src); + strelts = strelts / eltsize - 1; + + HOST_WIDE_INT maxelts = strelts; tree type = TREE_TYPE (src); if (tree size = TYPE_SIZE_UNIT (type)) if (tree_fits_shwi_p (size)) - maxelts = tree_to_uhwi (size); - - maxelts = maxelts / eltsize - 1; + { + maxelts = tree_to_uhwi (size); + maxelts = maxelts / eltsize - 1; + } /* PTR can point to the byte representation of any string type, including char* and wchar_t*. */ @@ -620,10 +627,12 @@ c_strlen (tree src, int only_value) if (byteoff && TREE_CODE (byteoff) != INTEGER_CST) { - /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't - compute the offset to the following null if we don't know where to + /* If the string has an internal NUL character followed by any + non-NUL characters (e.g., "foo\0bar"), we can't compute + the offset to the following NUL if we don't know where to start searching for it. */ - if (string_length (ptr, eltsize, maxelts) < maxelts) + unsigned len = string_length (ptr, eltsize, strelts); + if (len < strelts) { /* Return when an embedded null character is found. */ return NULL_TREE; @@ -633,12 +642,17 @@ c_strlen (tree src, int only_value) return ssize_int (0); /* We don't know the starting offset, but we do know that the string - has no internal zero bytes. We can assume that the offset falls - within the bounds of the string; otherwise, the programmer deserves - what he gets. Subtract the offset from the length of the string, - and return that. This would perhaps not be valid if we were dealing - with named arrays in addition to literal string constants. */ - return size_diffop_loc (loc, size_int (maxelts * eltsize), byteoff); + has no internal zero bytes. If the offset falls within the bounds + of the string subtract the offset from the length of the string, + and return that. Otherwise the length is zero. Take care to + use SAVE_EXPR in case the OFFSET has side-effects. */ + tree offsave = TREE_SIDE_EFFECTS (byteoff) ? save_expr (byteoff) : byteoff; + offsave = fold_convert (ssizetype, offsave); + tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave, + build_int_cst (ssizetype, len * eltsize)); + tree lenexp = size_diffop_loc (loc, ssize_int (strelts * eltsize), offsave); + return fold_build3_loc (loc, COND_EXPR, ssizetype, condexp, lenexp, + build_zero_cst (ssizetype)); } /* Offset from the beginning of the string in elements. */ @@ -3192,15 +3206,13 @@ check_access (tree exp, tree, tree, tree dstwrite, if (dstwrite) get_size_range (dstwrite, range); - /* This can happen at -O0. */ - if (range[0] && TREE_CODE (range[0]) != INTEGER_CST) - return false; - tree func = get_callee_fndecl (exp); /* First check the number of bytes to be written against the maximum object size. */ - if (range[0] && tree_int_cst_lt (maxobjsize, range[0])) + if (range[0] + && TREE_CODE (range[0]) == INTEGER_CST + && tree_int_cst_lt (maxobjsize, range[0])) { if (TREE_NO_WARNING (exp)) return false; @@ -3235,9 +3247,11 @@ check_access (tree exp, tree, tree, tree dstwrite, if (range[0] || !exactwrite || integer_all_onesp (dstwrite)) { if (range[0] + && TREE_CODE (range[0]) == INTEGER_CST && ((tree_fits_uhwi_p (dstsize) && tree_int_cst_lt (dstsize, range[0])) - || (tree_fits_uhwi_p (dstwrite) + || (dstwrite + && tree_fits_uhwi_p (dstwrite) && tree_int_cst_lt (dstwrite, range[0])))) { if (TREE_NO_WARNING (exp)) diff --git a/gcc/builtins.h b/gcc/builtins.h index c9229049e21..2e0a2f95379 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -57,6 +57,7 @@ extern unsigned int get_object_alignment (tree); extern bool get_pointer_alignment_1 (tree, unsigned int *, unsigned HOST_WIDE_INT *); extern unsigned int get_pointer_alignment (tree); +extern unsigned string_length (const void*, unsigned, unsigned); extern tree c_strlen (tree, int); extern void expand_builtin_setjmp_setup (rtx, rtx); extern void expand_builtin_setjmp_receiver (rtx); diff --git a/gcc/expr.c b/gcc/expr.c index f665e187ebb..de6709defd6 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11294,12 +11294,15 @@ string_constant (tree arg, tree *ptr_offset) tree idx = TREE_OPERAND (arg, 1); if (TREE_CODE (idx) != INTEGER_CST) { - /* Extract the variable index to prevent - get_addr_base_and_unit_offset() from failing due to - it. Use it later to compute the non-constant offset + /* From a pointer (but not array) argument extract the variable + index to prevent get_addr_base_and_unit_offset() from failing + due to it. Use it later to compute the non-constant offset into the string and return it to the caller. */ varidx = idx; ref = TREE_OPERAND (arg, 0); + + if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE) + return NULL_TREE; } } array = get_addr_base_and_unit_offset (ref, &base_off); @@ -11327,6 +11330,12 @@ string_constant (tree arg, tree *ptr_offset) tree offset; if (tree str = string_constant (arg0, &offset)) { + /* Avoid pointers to arrays (see bug 86622). */ + if (POINTER_TYPE_P (TREE_TYPE (arg)) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == ARRAY_TYPE + && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF) + return NULL_TREE; + tree type = TREE_TYPE (arg1); *ptr_offset = fold_build2 (PLUS_EXPR, type, offset, arg1); return str; @@ -11343,16 +11352,17 @@ string_constant (tree arg, tree *ptr_offset) { if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE) return NULL_TREE; - if (tree eltsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)))) - { - /* Add the scaled variable index to the constant offset. */ - tree eltoff = fold_build2 (MULT_EXPR, TREE_TYPE (offset), - fold_convert (sizetype, varidx), - eltsize); - offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset), offset, eltoff); - } - else - return NULL_TREE; + + gcc_assert (TREE_CODE (arg) == ARRAY_REF); + tree chartype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (arg, 0))); + if (TREE_CODE (chartype) != INTEGER_TYPE) + return NULL; + + tree charsize = array_ref_element_size (arg); + /* Set the non-constant offset to the non-constant index scaled + by the size of the character type. */ + offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset), + fold_convert (sizetype, varidx), charsize); } if (TREE_CODE (array) == STRING_CST) @@ -11371,11 +11381,6 @@ string_constant (tree arg, tree *ptr_offset) return NULL_TREE; if (TREE_CODE (init) == CONSTRUCTOR) { - if (TREE_CODE (arg) != ARRAY_REF - && TREE_CODE (arg) == COMPONENT_REF - && TREE_CODE (arg) == MEM_REF) - return NULL_TREE; - /* Convert the 64-bit constant offset to a wider type to avoid overflow. */ offset_int wioff; @@ -11391,11 +11396,15 @@ string_constant (tree arg, tree *ptr_offset) init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array, &fieldoff); HOST_WIDE_INT cstoff; - if (init && base_off.is_constant (&cstoff)) - { - cstoff = (cstoff - fieldoff) / BITS_PER_UNIT; - offset = build_int_cst (sizetype, cstoff); - } + if (!base_off.is_constant (&cstoff)) + return NULL_TREE; + + cstoff = (cstoff - fieldoff) / BITS_PER_UNIT; + tree off = build_int_cst (sizetype, cstoff); + if (varidx) + offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset), offset, off); + else + offset = off; } if (!init || TREE_CODE (init) != STRING_CST) @@ -11413,8 +11422,11 @@ string_constant (tree arg, tree *ptr_offset) const char a[4] = "abc\000\000"; The excess elements contribute to TREE_STRING_LENGTH() but not to strlen(). */ - unsigned HOST_WIDE_INT length - = strnlen (TREE_STRING_POINTER (init), TREE_STRING_LENGTH (init)); + unsigned HOST_WIDE_INT charsize + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (init)))); + unsigned HOST_WIDE_INT length = TREE_STRING_LENGTH (init); + length = string_length (TREE_STRING_POINTER (init), charsize, + length / charsize); if (compare_tree_int (array_size, length + 1) < 0) return NULL_TREE; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f8cf9eeb466..af40567347d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2018-07-24 Martin Sebor + + PR tree-optimization/86622 + PR tree-optimization/86532 + * gcc.c-torture/execute/strlen-2.c: New test. + * gcc.c-torture/execute/strlen-3.c: New test. + * gcc.c-torture/execute/strlen-4.c: New test. + 2018-07-24 David Malcolm PR tree-optimization/86636 diff --git a/gcc/testsuite/gcc.c-torture/execute/strlen-2.c b/gcc/testsuite/gcc.c-torture/execute/strlen-2.c new file mode 100644 index 00000000000..4519f6a4680 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/strlen-2.c @@ -0,0 +1,210 @@ +/* PR tree-optimization/86532 - Wrong code due to a wrong strlen folding */ + +extern __SIZE_TYPE__ strlen (const char*); + +static const char a[2][3] = { "1", "12" }; +static const char b[2][2][5] = { { "1", "12" }, { "123", "1234" } }; + +volatile int v0 = 0; +volatile int v1 = 1; +volatile int v2 = 2; + +#define A(expr) \ + ((expr) ? (void)0 : (__builtin_printf ("assertion on line %i: %s\n", \ + __LINE__, #expr), \ + __builtin_abort ())) + +void test_array_ref_2_3 (void) +{ + A (strlen (a[v0]) == 1); + A (strlen (&a[v0][v0]) == 1); + A (strlen (&a[0][v0]) == 1); + A (strlen (&a[v0][0]) == 1); + + A (strlen (a[v1]) == 2); + A (strlen (&a[v1][0]) == 2); + A (strlen (&a[1][v0]) == 2); + A (strlen (&a[v1][v0]) == 2); + + A (strlen (&a[v1][1]) == 1); + A (strlen (&a[v1][1]) == 1); + + A (strlen (&a[v1][2]) == 0); + A (strlen (&a[v1][v2]) == 0); + + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + + A (strlen (a[v0]) == 1); + A (strlen (&a[v0][v0]) == 1); + A (strlen (&a[i0][v0]) == 1); + A (strlen (&a[v0][i0]) == 1); + + A (strlen (a[v1]) == 2); + A (strlen (&a[v1][i0]) == 2); + A (strlen (&a[i1][v0]) == 2); + A (strlen (&a[v1][v0]) == 2); + + A (strlen (&a[v1][i1]) == 1); + A (strlen (&a[v1][i1]) == 1); + + A (strlen (&a[v1][i2]) == 0); + A (strlen (&a[v1][v2]) == 0); +} + +void test_array_off_2_3 (void) +{ + A (strlen (a[0] + 0) == 1); + A (strlen (a[0] + v0) == 1); + A (strlen (a[v0] + 0) == 1); + A (strlen (a[v0] + v0) == 1); + + A (strlen (a[v1] + 0) == 2); + A (strlen (a[1] + v0) == 2); + A (strlen (a[v1] + 0) == 2); + A (strlen (a[v1] + v0) == 2); + + A (strlen (a[v1] + 1) == 1); + A (strlen (a[v1] + v1) == 1); + + A (strlen (a[v1] + 2) == 0); + A (strlen (a[v1] + v2) == 0); + + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + + A (strlen (a[i0] + i0) == 1); + A (strlen (a[i0] + v0) == 1); + A (strlen (a[v0] + i0) == 1); + A (strlen (a[v0] + v0) == 1); + + A (strlen (a[v1] + i0) == 2); + A (strlen (a[i1] + v0) == 2); + A (strlen (a[v1] + i0) == 2); + A (strlen (a[v1] + v0) == 2); + + A (strlen (a[v1] + i1) == 1); + A (strlen (a[v1] + v1) == 1); + + A (strlen (a[v1] + i2) == 0); + A (strlen (a[v1] + v2) == 0); +} + +void test_array_ref_2_2_5 (void) +{ + A (strlen (b[0][v0]) == 1); + A (strlen (b[v0][0]) == 1); + + A (strlen (&b[0][0][v0]) == 1); + A (strlen (&b[0][v0][0]) == 1); + A (strlen (&b[v0][0][0]) == 1); + + A (strlen (&b[0][v0][v0]) == 1); + A (strlen (&b[v0][0][v0]) == 1); + A (strlen (&b[v0][v0][0]) == 1); + + A (strlen (b[0][v1]) == 2); + A (strlen (b[v1][0]) == 3); + + A (strlen (&b[0][0][v1]) == 0); + A (strlen (&b[0][v1][0]) == 2); + A (strlen (&b[v0][0][0]) == 1); + + A (strlen (&b[0][v0][v0]) == 1); + A (strlen (&b[v0][0][v0]) == 1); + A (strlen (&b[v0][v0][0]) == 1); + + A (strlen (&b[0][v1][v1]) == 1); + A (strlen (&b[v1][0][v1]) == 2); + A (strlen (&b[v1][v1][0]) == 4); + A (strlen (&b[v1][v1][1]) == 3); + A (strlen (&b[v1][v1][2]) == 2); + + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + + A (strlen (b[i0][v0]) == 1); + A (strlen (b[v0][i0]) == 1); + + A (strlen (&b[i0][i0][v0]) == 1); + A (strlen (&b[i0][v0][i0]) == 1); + A (strlen (&b[v0][i0][i0]) == 1); + + A (strlen (&b[i0][v0][v0]) == 1); + A (strlen (&b[v0][i0][v0]) == 1); + A (strlen (&b[v0][v0][i0]) == 1); + + A (strlen (b[i0][v1]) == 2); + A (strlen (b[v1][i0]) == 3); + + A (strlen (&b[i0][i0][v1]) == 0); + A (strlen (&b[i0][v1][i0]) == 2); + A (strlen (&b[v0][i0][i0]) == 1); + + A (strlen (&b[i0][v0][v0]) == 1); + A (strlen (&b[v0][i0][v0]) == 1); + A (strlen (&b[v0][v0][i0]) == 1); + + A (strlen (&b[i0][v1][v1]) == 1); + A (strlen (&b[v1][i0][v1]) == 2); + A (strlen (&b[v1][v1][i0]) == 4); + A (strlen (&b[v1][v1][i1]) == 3); + A (strlen (&b[v1][v1][i2]) == 2); +} + +void test_array_off_2_2_5 (void) +{ + A (strlen (b[0][0] + v0) == 1); + A (strlen (b[0][v0] + v0) == 1); + A (strlen (b[v0][0] + v0) == 1); + A (strlen (b[v0][v0] + v0) == 1); + + A (strlen (b[0][0] + v1) == 0); + A (strlen (b[0][v1] + 0) == 2); + A (strlen (b[v0][0] + 0) == 1); + + A (strlen (b[0][v0] + v0) == 1); + A (strlen (b[v0][0] + v0) == 1); + A (strlen (b[v0][v0] + 0) == 1); + + A (strlen (b[0][v1] + v1) == 1); + A (strlen (b[v1][0] + v1) == 2); + A (strlen (b[v1][v1] + 0) == 4); + A (strlen (b[v1][v1] + 1) == 3); + A (strlen (b[v1][v1] + 2) == 2); + + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + + A (strlen (b[i0][i0] + v0) == 1); + A (strlen (b[i0][v0] + v0) == 1); + A (strlen (b[v0][i0] + v0) == 1); + A (strlen (b[v0][v0] + v0) == 1); + + A (strlen (b[i0][i0] + v1) == 0); + A (strlen (b[i0][v1] + i0) == 2); + A (strlen (b[v0][i0] + i0) == 1); + + A (strlen (b[i0][v0] + v0) == 1); + A (strlen (b[v0][i0] + v0) == 1); + A (strlen (b[v0][v0] + i0) == 1); + + A (strlen (b[i0][v1] + v1) == 1); + A (strlen (b[v1][i0] + v1) == 2); + A (strlen (b[v1][v1] + i0) == 4); + A (strlen (b[v1][v1] + i1) == 3); + A (strlen (b[v1][v1] + i2) == 2); +} + +int main () +{ + test_array_ref_2_3 (); + test_array_off_2_3 (); + + test_array_ref_2_2_5 (); + test_array_off_2_2_5 (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/strlen-3.c b/gcc/testsuite/gcc.c-torture/execute/strlen-3.c new file mode 100644 index 00000000000..182afdd1fa6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/strlen-3.c @@ -0,0 +1,132 @@ +/* PR tree-optimization/86532 - Wrong code due to a wrong strlen folding + starting with r262522 + Exercise strlen() with a multi-dimensional array of strings with + embedded nuls. */ + +extern __SIZE_TYPE__ strlen (const char*); + +static const char a[2][3][9] = { + { "1", "1\0002" }, + { "12\0003", "123\0004" } +}; + +volatile int v0 = 0; +volatile int v1 = 1; +volatile int v2 = 2; +volatile int v3 = 3; +volatile int v4 = 4; +volatile int v5 = 5; +volatile int v6 = 6; +volatile int v7 = 7; + +#define A(expr) \ + ((expr) ? (void)0 : (__builtin_printf ("assertion on line %i: %s\n", \ + __LINE__, #expr), \ + __builtin_abort ())) + +void test_array_ref (void) +{ + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + int i3 = i2 + 1; + int i4 = i3 + 1; + int i5 = i4 + 1; + int i6 = i5 + 1; + int i7 = i6 + 1; + + A (strlen (a[0][0]) == 1); + A (strlen (a[0][1]) == 1); + + A (strlen (a[1][0]) == 2); + A (strlen (a[1][1]) == 3); + + A (strlen (&a[0][0][0]) == 1); + A (strlen (&a[0][1][0]) == 1); + + A (strlen (&a[1][0][0]) == 2); + A (strlen (&a[1][1][0]) == 3); + + A (strlen (&a[0][0][0] + 1) == 0); + A (strlen (&a[0][1][0] + 1) == 0); + A (strlen (&a[0][1][0] + 2) == 1); + A (strlen (&a[0][1][0] + 3) == 0); + A (strlen (&a[0][1][0] + 7) == 0); + + A (strlen (&a[1][0][0] + 1) == 1); + A (strlen (&a[1][1][0] + 1) == 2); + A (strlen (&a[1][1][0] + 2) == 1); + A (strlen (&a[1][1][0] + 7) == 0); + + + A (strlen (a[i0][i0]) == 1); + A (strlen (a[i0][i1]) == 1); + + A (strlen (a[i1][i0]) == 2); + A (strlen (a[i1][i1]) == 3); + + A (strlen (&a[i0][i0][i0]) == 1); + A (strlen (&a[i0][i1][i0]) == 1); + A (strlen (&a[i0][i1][i1]) == 0); + A (strlen (&a[i0][i1][i2]) == 1); + A (strlen (&a[i0][i1][i3]) == 0); + A (strlen (&a[i0][i1][i3]) == 0); + + A (strlen (&a[i1][i0][i0]) == 2); + A (strlen (&a[i1][i1][i0]) == 3); + A (strlen (&a[i1][i1][i1]) == 2); + A (strlen (&a[i1][i1][i2]) == 1); + A (strlen (&a[i1][i1][i3]) == 0); + A (strlen (&a[i1][i1][i4]) == 1); + A (strlen (&a[i1][i1][i5]) == 0); + A (strlen (&a[i1][i1][i6]) == 0); + A (strlen (&a[i1][i1][i7]) == 0); + + A (strlen (&a[i0][i0][i0] + i1) == 0); + A (strlen (&a[i0][i1][i0] + i1) == 0); + A (strlen (&a[i0][i1][i0] + i7) == 0); + + A (strlen (&a[i1][i0][i0] + i1) == 1); + A (strlen (&a[i1][i1][i0] + i1) == 2); + A (strlen (&a[i1][i1][i0] + i2) == 1); + A (strlen (&a[i1][i1][i0] + i3) == 0); + A (strlen (&a[i1][i1][i0] + i4) == 1); + A (strlen (&a[i1][i1][i0] + i5) == 0); + A (strlen (&a[i1][i1][i0] + i6) == 0); + A (strlen (&a[i1][i1][i0] + i7) == 0); + + + A (strlen (a[i0][i0]) == 1); + A (strlen (a[i0][i1]) == 1); + + A (strlen (a[i1][i0]) == 2); + A (strlen (a[i1][i1]) == 3); + + A (strlen (&a[i0][i0][i0]) == 1); + A (strlen (&a[i0][i1][i0]) == 1); + + A (strlen (&a[i1][i0][i0]) == 2); + A (strlen (&a[i1][i1][i0]) == 3); + + A (strlen (&a[i0][i0][i0] + v1) == 0); + A (strlen (&a[i0][i0][i0] + v2) == 0); + A (strlen (&a[i0][i0][i0] + v7) == 0); + + A (strlen (&a[i0][i1][i0] + v1) == 0); + A (strlen (&a[i0][i1][i0] + v2) == 1); + A (strlen (&a[i0][i1][i0] + v3) == 0); + + A (strlen (&a[i1][i0][i0] + v1) == 1); + A (strlen (&a[i1][i1][i0] + v1) == 2); + A (strlen (&a[i1][i1][i0] + v2) == 1); + A (strlen (&a[i1][i1][i0] + v3) == 0); + A (strlen (&a[i1][i1][i0] + v4) == 1); + A (strlen (&a[i1][i1][i0] + v5) == 0); + A (strlen (&a[i1][i1][i0] + v6) == 0); + A (strlen (&a[i1][i1][i0] + v7) == 0); +} + +int main (void) +{ + test_array_ref (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/strlen-4.c b/gcc/testsuite/gcc.c-torture/execute/strlen-4.c new file mode 100644 index 00000000000..c3b2c7712f6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/strlen-4.c @@ -0,0 +1,232 @@ +/* PR tree-optimization/86622 - incorrect strlen of array of array plus + variable offset + Exercise strlen() with a multi-dimensional array of strings with + offsets. */ + +extern int printf (const char*, ...); +extern __SIZE_TYPE__ strlen (const char*); + +typedef char A28[28]; +typedef A28 A3_28[3]; +typedef A3_28 A2_3_28[2]; + +static const A2_3_28 a = { + /* [0][0] [0][1] [0][2] */ + { "1\00012", "123\0001234", "12345\000123456" }, + /* [1][0] [1][1] [1][2] */ + { "1234567\00012345678", "123456789\0001234567890", "12345678901\000123456789012" } +}; + +volatile int v0 = 0; +volatile int v1 = 1; +volatile int v2 = 2; +volatile int v3 = 3; +volatile int v4 = 4; +volatile int v5 = 5; +volatile int v6 = 6; +volatile int v7 = 7; + +#define A(expr, N) \ + ((strlen (expr) == N) \ + ? (void)0 : (printf ("line %i: strlen (%s = \"%s\") != %i\n", \ + __LINE__, #expr, expr, N), \ + __builtin_abort ())) + +/* Verify that strlen() involving pointer to array arguments computes + the correct result. */ + +void test_array_ptr (void) +{ + /* Compute the length of the string at the refeenced array. */ + A (*(&a[0][0] + 0), 1); + A (*(&a[0][0] + 1), 3); + A (*(&a[0][0] + 2), 5); + + A (*(&a[0][1] - 1), 1); + A (*(&a[0][1] + 0), 3); + A (*(&a[0][1] + 1), 5); + + A (*(&a[0][2] - 2), 1); + A (*(&a[0][2] - 1), 3); + A (*(&a[0][2] + 0), 5); + + A (*(&a[1][0] + 0), 7); + A (*(&a[1][0] + 1), 9); + A (*(&a[1][0] + 2), 11); + + A (*(&a[1][1] - 1), 7); + A (*(&a[1][1] + 0), 9); + A (*(&a[1][1] + 1), 11); + + A (*(&a[1][2] - 2), 7); + A (*(&a[1][2] - 1), 9); + A (*(&a[1][2] - 0), 11); + + /* Compute the length of the string past the first nul. */ + A (*(&a[0][0] + 0) + 2, 2); + A (*(&a[0][0] + 1) + 4, 4); + A (*(&a[0][0] + 2) + 6, 6); + + /* Compute the length of the string past the second nul. */ + A (*(&a[0][0] + 0) + 5, 0); + A (*(&a[0][0] + 1) + 10, 0); + A (*(&a[0][0] + 2) + 14, 0); + + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + int i3 = i2 + 1; + int i4 = i3 + 1; + int i5 = i4 + 1; + + A (*(&a[0][0] + i0), 1); + A (*(&a[0][0] + i1), 3); + A (*(&a[0][0] + i2), 5); + + A (*(&a[0][1] - i1), 1); + A (*(&a[0][1] + i0), 3); + A (*(&a[0][1] + i1), 5); + + A (*(&a[0][2] - i2), 1); + A (*(&a[0][2] - i1), 3); + A (*(&a[0][2] + i0), 5); + + A (*(&a[1][0] + i0), 7); + A (*(&a[1][0] + i1), 9); + A (*(&a[1][0] + i2), 11); + + A (*(&a[1][1] - i1), 7); + A (*(&a[1][1] + i0), 9); + A (*(&a[1][1] + i1), 11); + + A (*(&a[1][2] - i2), 7); + A (*(&a[1][2] - i1), 9); + A (*(&a[1][2] - i0), 11); + + + A (*(&a[i0][i0] + i0), 1); + A (*(&a[i0][i0] + i1), 3); + A (*(&a[i0][i0] + i2), 5); + + A (*(&a[i0][i1] - i1), 1); + A (*(&a[i0][i1] + i0), 3); + A (*(&a[i0][i1] + i1), 5); + + A (*(&a[i0][i2] - i2), 1); + A (*(&a[i0][i2] - i1), 3); + A (*(&a[i0][i2] + i0), 5); + + A (*(&a[i1][i0] + i0), 7); + A (*(&a[i1][i0] + i1), 9); + A (*(&a[i1][i0] + i2), 11); + + A (*(&a[i1][i1] - i1), 7); + A (*(&a[i1][i1] + i0), 9); + A (*(&a[i1][i1] + i1), 11); + + A (*(&a[i1][i2] - i2), 7); + A (*(&a[i1][i2] - i1), 9); + A (*(&a[i1][i2] - i0), 11); + + + A (*(&a[i0][i0] + v0), 1); + A (*(&a[i0][i0] + v1), 3); + A (*(&a[i0][i0] + v2), 5); + + A (*(&a[i0][i1] - v1), 1); + A (*(&a[i0][i1] + v0), 3); + A (*(&a[i0][i1] + v1), 5); + + A (*(&a[i0][i2] - v2), 1); + A (*(&a[i0][i2] - v1), 3); + A (*(&a[i0][i2] + v0), 5); + + A (*(&a[i1][i0] + v0), 7); + A (*(&a[i1][i0] + v1), 9); + A (*(&a[i1][i0] + v2), 11); + + A (*(&a[i1][i1] - v1), 7); + A (*(&a[i1][i1] + v0), 9); + A (*(&a[i1][i1] + v1), 11); + + A (*(&a[i1][i2] - v2), 7); + A (*(&a[i1][i2] - v1), 9); + A (*(&a[i1][i2] - v0), 11); + + + A (*(&a[i0][i0] + v0) + i1, 0); + A (*(&a[i0][i0] + v1) + i2, 1); + A (*(&a[i0][i0] + v2) + i3, 2); + + A (*(&a[i0][i1] - v1) + v1, 0); + A (*(&a[i0][i1] + v0) + v3, 0); + A (*(&a[i0][i1] + v1) + v5, 0); + + A (*(&a[i0][v1] - i1) + i1, 0); + A (*(&a[i0][v1] + i0) + i3, 0); + A (*(&a[i0][v1] + i1) + i5, 0); +} + +static const A3_28* const pa0 = &a[0]; +static const A3_28* const pa1 = &a[1]; + +static const A3_28* const paa[] = { &a[0], &a[1] }; + +/* Verify that strlen() involving pointers and arrays of pointers + to array arguments computes the correct result. */ + +void test_ptr_array (void) +{ + int i0 = 0; + int i1 = i0 + 1; + int i2 = i1 + 1; + int i3 = i2 + 1; + + A (*((*pa0) + i0), 1); + A (*((*pa0) + i1), 3); + A (*((*pa0) + i2), 5); + + A (*(pa0[0] + i0), 1); + A (*(pa0[0] + i1), 3); + A (*(pa0[0] + i2), 5); + + A ((*pa0)[i0] + i1, 0); + A ((*pa0)[i1] + i2, 1); + A ((*pa0)[i2] + i3, 2); + + + A (*((*pa1) + i0), 7); + A (*((*pa1) + i1), 9); + A (*((*pa1) + i2), 11); + + A (*(pa1[0] + i0), 7); + A (*(pa1[0] + i1), 9); + A (*(pa1[0] + i2), 11); + + A ((*pa1)[i0] + i1, 6); + A ((*pa1)[i1] + i2, 7); + A ((*pa1)[i2] + i3, 8); + + A (*(*(paa[0]) + i0), 1); + A (*(*(paa[0]) + i1), 3); + A (*(*(paa[0]) + i2), 5); + + A (*(*(paa[1]) + i0), 7); + A (*(*(paa[1]) + i1), 9); + A (*(*(paa[1]) + i2), 11); + + A (*(*(paa[1]) - i1), 5); + A (*(*(paa[1]) - i2), 3); + A (*(*(paa[1]) - i3), 1); + + A (*(*(paa[0]) + i0) + i1, 0); + A (*(*(paa[0]) + i1) + i2, 1); + A (*(*(paa[0]) + i2) + i3, 2); +} + +int main (void) +{ + test_array_ptr (); + + test_ptr_array (); +}