Commit bfb9bd47 by Martin Sebor Committed by Martin Sebor

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
parent ae752f02
2018-07-24 Martin Sebor <msebor@redhat.com>
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 <richard.sandiford@arm.com> 2018-07-24 Richard Sandiford <richard.sandiford@arm.com>
PR tree-optimization/86618 PR tree-optimization/86618
......
...@@ -517,11 +517,11 @@ get_pointer_alignment (tree exp) ...@@ -517,11 +517,11 @@ get_pointer_alignment (tree exp)
return align; 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. [ 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. */ 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) string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
{ {
gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4); gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
...@@ -605,14 +605,21 @@ c_strlen (tree src, int only_value) ...@@ -605,14 +605,21 @@ c_strlen (tree src, int only_value)
/* Set MAXELTS to sizeof (SRC) / sizeof (*SRC) - 1, the maximum possible /* Set MAXELTS to sizeof (SRC) / sizeof (*SRC) - 1, the maximum possible
length of SRC. Prefer TYPE_SIZE() to TREE_STRING_LENGTH() if 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. */ in case the latter is less than the size of the array, such as when
HOST_WIDE_INT maxelts = TREE_STRING_LENGTH (src); 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); tree type = TREE_TYPE (src);
if (tree size = TYPE_SIZE_UNIT (type)) if (tree size = TYPE_SIZE_UNIT (type))
if (tree_fits_shwi_p (size)) if (tree_fits_shwi_p (size))
maxelts = tree_to_uhwi (size); {
maxelts = tree_to_uhwi (size);
maxelts = maxelts / eltsize - 1; maxelts = maxelts / eltsize - 1;
}
/* PTR can point to the byte representation of any string type, including /* PTR can point to the byte representation of any string type, including
char* and wchar_t*. */ char* and wchar_t*. */
...@@ -620,10 +627,12 @@ c_strlen (tree src, int only_value) ...@@ -620,10 +627,12 @@ c_strlen (tree src, int only_value)
if (byteoff && TREE_CODE (byteoff) != INTEGER_CST) if (byteoff && TREE_CODE (byteoff) != INTEGER_CST)
{ {
/* If the string has an internal zero byte (e.g., "foo\0bar"), we can't /* If the string has an internal NUL character followed by any
compute the offset to the following null if we don't know where to 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. */ 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 when an embedded null character is found. */
return NULL_TREE; return NULL_TREE;
...@@ -633,12 +642,17 @@ c_strlen (tree src, int only_value) ...@@ -633,12 +642,17 @@ c_strlen (tree src, int only_value)
return ssize_int (0); return ssize_int (0);
/* We don't know the starting offset, but we do know that the string /* 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 has no internal zero bytes. If the offset falls within the bounds
within the bounds of the string; otherwise, the programmer deserves of the string subtract the offset from the length of the string,
what he gets. Subtract the offset from the length of the string, and return that. Otherwise the length is zero. Take care to
and return that. This would perhaps not be valid if we were dealing use SAVE_EXPR in case the OFFSET has side-effects. */
with named arrays in addition to literal string constants. */ tree offsave = TREE_SIDE_EFFECTS (byteoff) ? save_expr (byteoff) : byteoff;
return size_diffop_loc (loc, size_int (maxelts * eltsize), 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. */ /* Offset from the beginning of the string in elements. */
...@@ -3192,15 +3206,13 @@ check_access (tree exp, tree, tree, tree dstwrite, ...@@ -3192,15 +3206,13 @@ check_access (tree exp, tree, tree, tree dstwrite,
if (dstwrite) if (dstwrite)
get_size_range (dstwrite, range); 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); tree func = get_callee_fndecl (exp);
/* First check the number of bytes to be written against the maximum /* First check the number of bytes to be written against the maximum
object size. */ 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)) if (TREE_NO_WARNING (exp))
return false; return false;
...@@ -3235,9 +3247,11 @@ check_access (tree exp, tree, tree, tree dstwrite, ...@@ -3235,9 +3247,11 @@ check_access (tree exp, tree, tree, tree dstwrite,
if (range[0] || !exactwrite || integer_all_onesp (dstwrite)) if (range[0] || !exactwrite || integer_all_onesp (dstwrite))
{ {
if (range[0] if (range[0]
&& TREE_CODE (range[0]) == INTEGER_CST
&& ((tree_fits_uhwi_p (dstsize) && ((tree_fits_uhwi_p (dstsize)
&& tree_int_cst_lt (dstsize, range[0])) && 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])))) && tree_int_cst_lt (dstwrite, range[0]))))
{ {
if (TREE_NO_WARNING (exp)) if (TREE_NO_WARNING (exp))
......
...@@ -57,6 +57,7 @@ extern unsigned int get_object_alignment (tree); ...@@ -57,6 +57,7 @@ extern unsigned int get_object_alignment (tree);
extern bool get_pointer_alignment_1 (tree, unsigned int *, extern bool get_pointer_alignment_1 (tree, unsigned int *,
unsigned HOST_WIDE_INT *); unsigned HOST_WIDE_INT *);
extern unsigned int get_pointer_alignment (tree); extern unsigned int get_pointer_alignment (tree);
extern unsigned string_length (const void*, unsigned, unsigned);
extern tree c_strlen (tree, int); extern tree c_strlen (tree, int);
extern void expand_builtin_setjmp_setup (rtx, rtx); extern void expand_builtin_setjmp_setup (rtx, rtx);
extern void expand_builtin_setjmp_receiver (rtx); extern void expand_builtin_setjmp_receiver (rtx);
......
...@@ -11294,12 +11294,15 @@ string_constant (tree arg, tree *ptr_offset) ...@@ -11294,12 +11294,15 @@ string_constant (tree arg, tree *ptr_offset)
tree idx = TREE_OPERAND (arg, 1); tree idx = TREE_OPERAND (arg, 1);
if (TREE_CODE (idx) != INTEGER_CST) if (TREE_CODE (idx) != INTEGER_CST)
{ {
/* Extract the variable index to prevent /* From a pointer (but not array) argument extract the variable
get_addr_base_and_unit_offset() from failing due to index to prevent get_addr_base_and_unit_offset() from failing
it. Use it later to compute the non-constant offset due to it. Use it later to compute the non-constant offset
into the string and return it to the caller. */ into the string and return it to the caller. */
varidx = idx; varidx = idx;
ref = TREE_OPERAND (arg, 0); 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); array = get_addr_base_and_unit_offset (ref, &base_off);
...@@ -11327,6 +11330,12 @@ string_constant (tree arg, tree *ptr_offset) ...@@ -11327,6 +11330,12 @@ string_constant (tree arg, tree *ptr_offset)
tree offset; tree offset;
if (tree str = string_constant (arg0, &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); tree type = TREE_TYPE (arg1);
*ptr_offset = fold_build2 (PLUS_EXPR, type, offset, arg1); *ptr_offset = fold_build2 (PLUS_EXPR, type, offset, arg1);
return str; return str;
...@@ -11343,16 +11352,17 @@ string_constant (tree arg, tree *ptr_offset) ...@@ -11343,16 +11352,17 @@ string_constant (tree arg, tree *ptr_offset)
{ {
if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE) if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE)
return NULL_TREE; return NULL_TREE;
if (tree eltsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array))))
{ gcc_assert (TREE_CODE (arg) == ARRAY_REF);
/* Add the scaled variable index to the constant offset. */ tree chartype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (arg, 0)));
tree eltoff = fold_build2 (MULT_EXPR, TREE_TYPE (offset), if (TREE_CODE (chartype) != INTEGER_TYPE)
fold_convert (sizetype, varidx), return NULL;
eltsize);
offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset), offset, eltoff); tree charsize = array_ref_element_size (arg);
} /* Set the non-constant offset to the non-constant index scaled
else by the size of the character type. */
return NULL_TREE; offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset),
fold_convert (sizetype, varidx), charsize);
} }
if (TREE_CODE (array) == STRING_CST) if (TREE_CODE (array) == STRING_CST)
...@@ -11371,11 +11381,6 @@ string_constant (tree arg, tree *ptr_offset) ...@@ -11371,11 +11381,6 @@ string_constant (tree arg, tree *ptr_offset)
return NULL_TREE; return NULL_TREE;
if (TREE_CODE (init) == CONSTRUCTOR) 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 /* Convert the 64-bit constant offset to a wider type to avoid
overflow. */ overflow. */
offset_int wioff; offset_int wioff;
...@@ -11391,11 +11396,15 @@ string_constant (tree arg, tree *ptr_offset) ...@@ -11391,11 +11396,15 @@ string_constant (tree arg, tree *ptr_offset)
init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array, init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array,
&fieldoff); &fieldoff);
HOST_WIDE_INT cstoff; HOST_WIDE_INT cstoff;
if (init && base_off.is_constant (&cstoff)) if (!base_off.is_constant (&cstoff))
{ return NULL_TREE;
cstoff = (cstoff - fieldoff) / BITS_PER_UNIT;
offset = build_int_cst (sizetype, cstoff); 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) if (!init || TREE_CODE (init) != STRING_CST)
...@@ -11413,8 +11422,11 @@ string_constant (tree arg, tree *ptr_offset) ...@@ -11413,8 +11422,11 @@ string_constant (tree arg, tree *ptr_offset)
const char a[4] = "abc\000\000"; const char a[4] = "abc\000\000";
The excess elements contribute to TREE_STRING_LENGTH() The excess elements contribute to TREE_STRING_LENGTH()
but not to strlen(). */ but not to strlen(). */
unsigned HOST_WIDE_INT length unsigned HOST_WIDE_INT charsize
= strnlen (TREE_STRING_POINTER (init), TREE_STRING_LENGTH (init)); = 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) if (compare_tree_int (array_size, length + 1) < 0)
return NULL_TREE; return NULL_TREE;
......
2018-07-24 Martin Sebor <msebor@redhat.com>
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 <dmalcolm@redhat.com> 2018-07-24 David Malcolm <dmalcolm@redhat.com>
PR tree-optimization/86636 PR tree-optimization/86636
......
/* 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 ();
}
/* 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 ();
}
/* 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 ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment