gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range rather than set_range_info.
* gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range rather than set_range_info. * tree-ssa-strlen.c (set_strlen_range): Extracted from maybe_set_strlen_range. Handle potentially boundary crossing cases more conservatively. (maybe_set_strlen_range): Parts refactored into set_strlen_range. Call set_strlen_range. * tree-ssa-strlen.h (set_strlen_range): Add prototype. * gcc.dg/strlenopt-36.c: Update. * gcc.dg/strlenopt-45.c: Update. * gcc.c-torture/execute/strlen-5.c: New test. * gcc.c-torture/execute/strlen-6.c: New test. * gcc.c-torture/execute/strlen-7.c: New test. Co-Authored-By: Jeff Law <law@redhat.com> From-SVN: r267531
This commit is contained in:
parent
ec1faddf89
commit
d4bf69750d
|
@ -1,6 +1,16 @@
|
|||
2019-01-02 Martin Sebor <msebor@redhat.com>
|
||||
Jeff Law <law@redhat.com>
|
||||
|
||||
|
||||
* gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range
|
||||
rather than set_range_info.
|
||||
* tree-ssa-strlen.c (set_strlen_range): Extracted from
|
||||
maybe_set_strlen_range. Handle potentially boundary crossing
|
||||
cases more conservatively.
|
||||
(maybe_set_strlen_range): Parts refactored into set_strlen_range.
|
||||
Call set_strlen_range.
|
||||
* tree-ssa-strlen.h (set_strlen_range): Add prototype.
|
||||
|
||||
PR middle-end/88663
|
||||
* gimple-fold.c (get_range_strlen): Update prototype to no longer
|
||||
need the flexp argument.
|
||||
|
|
|
@ -3739,10 +3739,9 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Set the strlen() range to [0, MAXLEN]. */
|
||||
if (tree lhs = gimple_call_lhs (stmt))
|
||||
if (TREE_CODE (lhs) == SSA_NAME
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
||||
set_range_info (lhs, VR_RANGE, minlen, maxlen);
|
||||
set_strlen_range (lhs, maxlen);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2019-01-02 Martin Sebor <msebor@redhat.com>
|
||||
Jeff Law <law@redhat.com>
|
||||
|
||||
* gcc.dg/strlenopt-36.c: Update.
|
||||
* gcc.dg/strlenopt-45.c: Update.
|
||||
* gcc.c-torture/execute/strlen-5.c: New test.
|
||||
* gcc.c-torture/execute/strlen-6.c: New test.
|
||||
* gcc.c-torture/execute/strlen-7.c: New test.
|
||||
|
||||
2019-01-02 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR testsuite/87304
|
||||
|
|
|
@ -0,0 +1,653 @@
|
|||
/* Test to verify that even strictly undefined strlen() calls with
|
||||
unterminated character arrays yield the "expected" results when
|
||||
the terminating nul is present in a subsequent suobobject. */
|
||||
|
||||
extern __SIZE_TYPE__ strlen (const char *);
|
||||
|
||||
unsigned nfails;
|
||||
|
||||
#define A(expr, N) \
|
||||
do { \
|
||||
const char *s = (expr); \
|
||||
unsigned n = strlen (s); \
|
||||
((n == N) \
|
||||
? 0 \
|
||||
: (__builtin_printf ("line %i: strlen (%s = \"%s\")" \
|
||||
" == %u failed\n", \
|
||||
__LINE__, #expr, s, N), \
|
||||
++nfails)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
int idx;
|
||||
|
||||
|
||||
const char ca[][4] = {
|
||||
{ '1', '2', '3', '4' }, { '5' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7', '8' },
|
||||
{ '9' }
|
||||
};
|
||||
|
||||
static void test_const_global_arrays (void)
|
||||
{
|
||||
A (ca[0], 5);
|
||||
A (&ca[0][0], 5);
|
||||
A (&ca[0][1], 4);
|
||||
A (&ca[0][3], 2);
|
||||
|
||||
int i = 0;
|
||||
A (ca[i], 5);
|
||||
A (&ca[i][0], 5);
|
||||
A (&ca[i][1], 4);
|
||||
A (&ca[i][3], 2);
|
||||
|
||||
int j = i;
|
||||
A (&ca[i][i], 5);
|
||||
A (&ca[i][j + 1], 4);
|
||||
A (&ca[i][j + 2], 3);
|
||||
|
||||
A (&ca[idx][i], 5);
|
||||
A (&ca[idx][j + 1], 4);
|
||||
A (&ca[idx][j + 2], 3);
|
||||
|
||||
A (&ca[idx][idx], 5);
|
||||
A (&ca[idx][idx + 1], 4);
|
||||
A (&ca[idx][idx + 2], 3);
|
||||
|
||||
A (&ca[0][++j], 4);
|
||||
A (&ca[0][++j], 3);
|
||||
A (&ca[0][++j], 2);
|
||||
|
||||
if (j != 3)
|
||||
++nfails;
|
||||
}
|
||||
|
||||
|
||||
static void test_const_local_arrays (void)
|
||||
{
|
||||
const char a[][4] = {
|
||||
{ '1', '2', '3', '4' }, { '5' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7', '8' },
|
||||
{ '9' }
|
||||
};
|
||||
|
||||
A (a[0], 5);
|
||||
A (&a[0][0], 5);
|
||||
A (&a[0][1], 4);
|
||||
A (&a[0][3], 2);
|
||||
|
||||
int i = 0;
|
||||
A (a[i], 5);
|
||||
A (&a[i][0], 5);
|
||||
A (&a[i][1], 4);
|
||||
A (&a[i][3], 2);
|
||||
|
||||
int j = i;
|
||||
A (&a[i][i], 5);
|
||||
A (&a[i][j + 1], 4);
|
||||
A (&a[i][j + 2], 3);
|
||||
|
||||
A (&a[idx][i], 5);
|
||||
A (&a[idx][j + 1], 4);
|
||||
A (&a[idx][j + 2], 3);
|
||||
|
||||
A (&a[idx][idx], 5);
|
||||
A (&a[idx][idx + 1], 4);
|
||||
A (&a[idx][idx + 2], 3);
|
||||
|
||||
A (&a[0][++j], 4);
|
||||
A (&a[0][++j], 3);
|
||||
A (&a[0][++j], 2);
|
||||
|
||||
if (j != 3)
|
||||
++nfails;
|
||||
}
|
||||
|
||||
|
||||
char va[][4] = {
|
||||
{ '1', '2', '3', '4' }, { '5' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7', '8' },
|
||||
{ '9' }
|
||||
};
|
||||
|
||||
static void test_nonconst_global_arrays (void)
|
||||
{
|
||||
{
|
||||
A (va[0], 5);
|
||||
A (&va[0][0], 5);
|
||||
A (&va[0][1], 4);
|
||||
A (&va[0][3], 2);
|
||||
|
||||
int i = 0;
|
||||
A (va[i], 5);
|
||||
A (&va[i][0], 5);
|
||||
A (&va[i][1], 4);
|
||||
A (&va[i][3], 2);
|
||||
|
||||
int j = i;
|
||||
A (&va[i][i], 5);
|
||||
A (&va[i][j + 1], 4);
|
||||
A (&va[i][j + 2], 3);
|
||||
|
||||
A (&va[idx][i], 5);
|
||||
A (&va[idx][j + 1], 4);
|
||||
A (&va[idx][j + 2], 3);
|
||||
|
||||
A (&va[idx][idx], 5);
|
||||
A (&va[idx][idx + 1], 4);
|
||||
A (&va[idx][idx + 2], 3);
|
||||
}
|
||||
|
||||
{
|
||||
A (va[2], 6);
|
||||
A (&va[2][0], 6);
|
||||
A (&va[2][1], 5);
|
||||
A (&va[2][3], 3);
|
||||
|
||||
int i = 2;
|
||||
A (va[i], 6);
|
||||
A (&va[i][0], 6);
|
||||
A (&va[i][1], 5);
|
||||
A (&va[i][3], 3);
|
||||
|
||||
int j = i - 1;
|
||||
A (&va[i][j - 1], 6);
|
||||
A (&va[i][j], 5);
|
||||
A (&va[i][j + 1], 4);
|
||||
|
||||
A (&va[idx + 2][i - 1], 5);
|
||||
A (&va[idx + 2][j], 5);
|
||||
A (&va[idx + 2][j + 1], 4);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
A (&va[0][++j], 4);
|
||||
A (&va[0][++j], 3);
|
||||
A (&va[0][++j], 2);
|
||||
|
||||
if (j != 3)
|
||||
++nfails;
|
||||
}
|
||||
|
||||
|
||||
static void test_nonconst_local_arrays (void)
|
||||
{
|
||||
char a[][4] = {
|
||||
{ '1', '2', '3', '4' }, { '5' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7' },
|
||||
{ '1', '2', '3', '4' }, { '5', '6', '7', '8' },
|
||||
{ '9' }
|
||||
};
|
||||
|
||||
A (a[0], 5);
|
||||
A (&a[0][0], 5);
|
||||
A (&a[0][1], 4);
|
||||
A (&a[0][3], 2);
|
||||
|
||||
int i = 0;
|
||||
A (a[i], 5);
|
||||
A (&a[i][0], 5);
|
||||
A (&a[i][1], 4);
|
||||
A (&a[i][3], 2);
|
||||
|
||||
int j = i;
|
||||
A (&a[i][i], 5);
|
||||
A (&a[i][j + 1], 4);
|
||||
A (&a[i][j + 2], 3);
|
||||
|
||||
A (&a[idx][i], 5);
|
||||
A (&a[idx][j + 1], 4);
|
||||
A (&a[idx][j + 2], 3);
|
||||
|
||||
A (&a[idx][idx], 5);
|
||||
A (&a[idx][idx + 1], 4);
|
||||
A (&a[idx][idx + 2], 3);
|
||||
|
||||
A (&a[0][++j], 4);
|
||||
A (&a[0][++j], 3);
|
||||
A (&a[0][++j], 2);
|
||||
|
||||
if (j != 3)
|
||||
++nfails;
|
||||
}
|
||||
|
||||
|
||||
struct MemArrays { char a[4], b[4]; };
|
||||
|
||||
const struct MemArrays cma[] = {
|
||||
{ { '1', '2', '3', '4' }, { '5' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
|
||||
{ { '9' }, { '\0' } }
|
||||
};
|
||||
|
||||
static void test_const_global_member_arrays (void)
|
||||
{
|
||||
{
|
||||
A (cma[0].a, 5);
|
||||
A (&cma[0].a[0], 5);
|
||||
A (&cma[0].a[1], 4);
|
||||
A (&cma[0].a[2], 3);
|
||||
|
||||
int i = 0;
|
||||
A (cma[i].a, 5);
|
||||
A (&cma[i].a[0], 5);
|
||||
A (&cma[i].a[1], 4);
|
||||
A (&cma[i].a[2], 3);
|
||||
|
||||
int j = i;
|
||||
A (&cma[i].a[j], 5);
|
||||
A (&cma[i].a[j + 1], 4);
|
||||
A (&cma[i].a[j + 2], 3);
|
||||
|
||||
A (&cma[idx].a[i], 5);
|
||||
A (&cma[idx].a[j + 1], 4);
|
||||
A (&cma[idx].a[j + 2], 3);
|
||||
|
||||
A (&cma[idx].a[idx], 5);
|
||||
A (&cma[idx].a[idx + 1], 4);
|
||||
A (&cma[idx].a[idx + 2], 3);
|
||||
}
|
||||
|
||||
{
|
||||
A (cma[1].a, 6);
|
||||
A (&cma[1].a[0], 6);
|
||||
A (&cma[1].a[1], 5);
|
||||
A (&cma[1].a[2], 4);
|
||||
|
||||
int i = 1;
|
||||
A (cma[i].a, 6);
|
||||
A (&cma[i].a[0], 6);
|
||||
A (&cma[i].a[1], 5);
|
||||
A (&cma[i].a[2], 4);
|
||||
|
||||
int j = i - 1;
|
||||
A (&cma[i].a[j], 6);
|
||||
A (&cma[i].a[j + 1], 5);
|
||||
A (&cma[i].a[j + 2], 4);
|
||||
|
||||
A (&cma[idx + 1].a[j], 6);
|
||||
A (&cma[idx + 1].a[j + 1], 5);
|
||||
A (&cma[idx + 1].a[j + 2], 4);
|
||||
|
||||
A (&cma[idx + 1].a[idx], 6);
|
||||
A (&cma[idx + 1].a[idx + 1], 5);
|
||||
A (&cma[idx + 1].a[idx + 2], 4);
|
||||
}
|
||||
|
||||
{
|
||||
A (cma[4].a, 9);
|
||||
A (&cma[4].a[0], 9);
|
||||
A (&cma[4].a[1], 8);
|
||||
A (&cma[4].b[0], 5);
|
||||
|
||||
int i = 4;
|
||||
A (cma[i].a, 9);
|
||||
A (&cma[i].a[0], 9);
|
||||
A (&cma[i].a[1], 8);
|
||||
A (&cma[i].b[0], 5);
|
||||
|
||||
int j = i - 1;
|
||||
A (&cma[i].a[j], 6);
|
||||
A (&cma[i].a[j + 1], 5);
|
||||
A (&cma[i].b[j - 2], 4);
|
||||
|
||||
A (&cma[idx + 4].a[j], 6);
|
||||
A (&cma[idx + 4].a[j + 1], 5);
|
||||
A (&cma[idx + 4].b[j - 2], 4);
|
||||
|
||||
A (&cma[idx + 4].a[idx], 9);
|
||||
A (&cma[idx + 4].a[idx + 1], 8);
|
||||
A (&cma[idx + 4].b[idx + 1], 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_const_local_member_arrays (void)
|
||||
{
|
||||
const struct MemArrays ma[] = {
|
||||
{ { '1', '2', '3', '4' }, { '5' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
|
||||
{ { '9' }, { '\0' } }
|
||||
};
|
||||
|
||||
{
|
||||
A (ma[0].a, 5);
|
||||
A (&ma[0].a[0], 5);
|
||||
A (&ma[0].a[1], 4);
|
||||
A (&ma[0].a[2], 3);
|
||||
|
||||
int i = 0;
|
||||
A (ma[i].a, 5);
|
||||
A (&ma[i].a[0], 5);
|
||||
A (&ma[i].a[1], 4);
|
||||
A (&ma[i].a[2], 3);
|
||||
|
||||
int j = i;
|
||||
A (&ma[i].a[j], 5);
|
||||
A (&ma[i].a[j + 1], 4);
|
||||
A (&ma[i].a[j + 2], 3);
|
||||
|
||||
A (&ma[idx].a[i], 5);
|
||||
A (&ma[idx].a[j + 1], 4);
|
||||
A (&ma[idx].a[j + 2], 3);
|
||||
|
||||
A (&ma[idx].a[idx], 5);
|
||||
A (&ma[idx].a[idx + 1], 4);
|
||||
A (&ma[idx].a[idx + 2], 3);
|
||||
}
|
||||
|
||||
{
|
||||
A (ma[1].a, 6);
|
||||
A (&ma[1].a[0], 6);
|
||||
A (&ma[1].a[1], 5);
|
||||
A (&ma[1].a[2], 4);
|
||||
|
||||
int i = 1;
|
||||
A (ma[i].a, 6);
|
||||
A (&ma[i].a[0], 6);
|
||||
A (&ma[i].a[1], 5);
|
||||
A (&ma[i].a[2], 4);
|
||||
|
||||
int j = i - 1;
|
||||
A (&ma[i].a[j], 6);
|
||||
A (&ma[i].a[j + 1], 5);
|
||||
A (&ma[i].a[j + 2], 4);
|
||||
|
||||
A (&ma[idx + 1].a[j], 6);
|
||||
A (&ma[idx + 1].a[j + 1], 5);
|
||||
A (&ma[idx + 1].a[j + 2], 4);
|
||||
|
||||
A (&ma[idx + 1].a[idx], 6);
|
||||
A (&ma[idx + 1].a[idx + 1], 5);
|
||||
A (&ma[idx + 1].a[idx + 2], 4);
|
||||
}
|
||||
|
||||
{
|
||||
A (ma[4].a, 9);
|
||||
A (&ma[4].a[0], 9);
|
||||
A (&ma[4].a[1], 8);
|
||||
A (&ma[4].b[0], 5);
|
||||
|
||||
int i = 4;
|
||||
A (ma[i].a, 9);
|
||||
A (&ma[i].a[0], 9);
|
||||
A (&ma[i].a[1], 8);
|
||||
A (&ma[i].b[0], 5);
|
||||
|
||||
int j = i - 1;
|
||||
A (&ma[i].a[j], 6);
|
||||
A (&ma[i].a[j + 1], 5);
|
||||
A (&ma[i].b[j - 2], 4);
|
||||
|
||||
A (&ma[idx + 4].a[j], 6);
|
||||
A (&ma[idx + 4].a[j + 1], 5);
|
||||
A (&ma[idx + 4].b[j - 2], 4);
|
||||
|
||||
A (&ma[idx + 4].a[idx], 9);
|
||||
A (&ma[idx + 4].a[idx + 1], 8);
|
||||
A (&ma[idx + 4].b[idx + 1], 4);
|
||||
}
|
||||
}
|
||||
|
||||
struct MemArrays vma[] = {
|
||||
{ { '1', '2', '3', '4' }, { '5' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
|
||||
{ { '9' }, { '\0' } }
|
||||
};
|
||||
|
||||
static void test_nonconst_global_member_arrays (void)
|
||||
{
|
||||
{
|
||||
A (vma[0].a, 5);
|
||||
A (&vma[0].a[0], 5);
|
||||
A (&vma[0].a[1], 4);
|
||||
A (&vma[0].a[2], 3);
|
||||
|
||||
int i = 0;
|
||||
A (vma[i].a, 5);
|
||||
A (&vma[i].a[0], 5);
|
||||
A (&vma[i].a[1], 4);
|
||||
A (&vma[i].a[2], 3);
|
||||
|
||||
int j = i;
|
||||
A (&vma[i].a[j], 5);
|
||||
A (&vma[i].a[j + 1], 4);
|
||||
A (&vma[i].a[j + 2], 3);
|
||||
|
||||
A (&vma[idx].a[i], 5);
|
||||
A (&vma[idx].a[j + 1], 4);
|
||||
A (&vma[idx].a[j + 2], 3);
|
||||
|
||||
A (&vma[idx].a[idx], 5);
|
||||
A (&vma[idx].a[idx + 1], 4);
|
||||
A (&vma[idx].a[idx + 2], 3);
|
||||
}
|
||||
|
||||
{
|
||||
A (vma[1].a, 6);
|
||||
A (&vma[1].a[0], 6);
|
||||
A (&vma[1].a[1], 5);
|
||||
A (&vma[1].a[2], 4);
|
||||
|
||||
int i = 1;
|
||||
A (vma[i].a, 6);
|
||||
A (&vma[i].a[0], 6);
|
||||
A (&vma[i].a[1], 5);
|
||||
A (&vma[i].a[2], 4);
|
||||
|
||||
int j = i - 1;
|
||||
A (&vma[i].a[j], 6);
|
||||
A (&vma[i].a[j + 1], 5);
|
||||
A (&vma[i].a[j + 2], 4);
|
||||
|
||||
A (&vma[idx + 1].a[j], 6);
|
||||
A (&vma[idx + 1].a[j + 1], 5);
|
||||
A (&vma[idx + 1].a[j + 2], 4);
|
||||
|
||||
A (&vma[idx + 1].a[idx], 6);
|
||||
A (&vma[idx + 1].a[idx + 1], 5);
|
||||
A (&vma[idx + 1].a[idx + 2], 4);
|
||||
}
|
||||
|
||||
{
|
||||
A (vma[4].a, 9);
|
||||
A (&vma[4].a[0], 9);
|
||||
A (&vma[4].a[1], 8);
|
||||
A (&vma[4].b[0], 5);
|
||||
|
||||
int i = 4;
|
||||
A (vma[i].a, 9);
|
||||
A (&vma[i].a[0], 9);
|
||||
A (&vma[i].a[1], 8);
|
||||
A (&vma[i].b[0], 5);
|
||||
|
||||
int j = i - 1;
|
||||
A (&vma[i].a[j], 6);
|
||||
A (&vma[i].a[j + 1], 5);
|
||||
A (&vma[i].b[j - 2], 4);
|
||||
|
||||
A (&vma[idx + 4].a[j], 6);
|
||||
A (&vma[idx + 4].a[j + 1], 5);
|
||||
A (&vma[idx + 4].b[j - 2], 4);
|
||||
|
||||
A (&vma[idx + 4].a[idx], 9);
|
||||
A (&vma[idx + 4].a[idx + 1], 8);
|
||||
A (&vma[idx + 4].b[idx + 1], 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_nonconst_local_member_arrays (void)
|
||||
{
|
||||
struct MemArrays ma[] = {
|
||||
{ { '1', '2', '3', '4' }, { '5' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7' } },
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
|
||||
{ { '9' }, { '\0' } }
|
||||
};
|
||||
|
||||
{
|
||||
A (ma[0].a, 5);
|
||||
A (&ma[0].a[0], 5);
|
||||
A (&ma[0].a[1], 4);
|
||||
A (&ma[0].a[2], 3);
|
||||
|
||||
int i = 0;
|
||||
A (ma[i].a, 5);
|
||||
A (&ma[i].a[0], 5);
|
||||
A (&ma[i].a[1], 4);
|
||||
A (&ma[i].a[2], 3);
|
||||
|
||||
int j = i;
|
||||
A (&ma[i].a[j], 5);
|
||||
A (&ma[i].a[j + 1], 4);
|
||||
A (&ma[i].a[j + 2], 3);
|
||||
|
||||
A (&ma[idx].a[i], 5);
|
||||
A (&ma[idx].a[j + 1], 4);
|
||||
A (&ma[idx].a[j + 2], 3);
|
||||
|
||||
A (&ma[idx].a[idx], 5);
|
||||
A (&ma[idx].a[idx + 1], 4);
|
||||
A (&ma[idx].a[idx + 2], 3);
|
||||
}
|
||||
|
||||
{
|
||||
A (ma[1].a, 6);
|
||||
A (&ma[1].a[0], 6);
|
||||
A (&ma[1].a[1], 5);
|
||||
A (&ma[1].a[2], 4);
|
||||
|
||||
int i = 1;
|
||||
A (ma[i].a, 6);
|
||||
A (&ma[i].a[0], 6);
|
||||
A (&ma[i].a[1], 5);
|
||||
A (&ma[i].a[2], 4);
|
||||
|
||||
int j = i - 1;
|
||||
A (&ma[i].a[j], 6);
|
||||
A (&ma[i].a[j + 1], 5);
|
||||
A (&ma[i].a[j + 2], 4);
|
||||
|
||||
A (&ma[idx + 1].a[j], 6);
|
||||
A (&ma[idx + 1].a[j + 1], 5);
|
||||
A (&ma[idx + 1].a[j + 2], 4);
|
||||
|
||||
A (&ma[idx + 1].a[idx], 6);
|
||||
A (&ma[idx + 1].a[idx + 1], 5);
|
||||
A (&ma[idx + 1].a[idx + 2], 4);
|
||||
}
|
||||
|
||||
{
|
||||
A (ma[4].a, 9);
|
||||
A (&ma[4].a[0], 9);
|
||||
A (&ma[4].a[1], 8);
|
||||
A (&ma[4].b[0], 5);
|
||||
|
||||
int i = 4;
|
||||
A (ma[i].a, 9);
|
||||
A (&ma[i].a[0], 9);
|
||||
A (&ma[i].a[1], 8);
|
||||
A (&ma[i].b[0], 5);
|
||||
|
||||
int j = i - 1;
|
||||
A (&ma[i].a[j], 6);
|
||||
A (&ma[i].a[j + 1], 5);
|
||||
A (&ma[i].b[j - 2], 4);
|
||||
|
||||
A (&ma[idx + 4].a[j], 6);
|
||||
A (&ma[idx + 4].a[j + 1], 5);
|
||||
A (&ma[idx + 4].b[j - 2], 4);
|
||||
|
||||
A (&ma[idx + 4].a[idx], 9);
|
||||
A (&ma[idx + 4].a[idx + 1], 8);
|
||||
A (&ma[idx + 4].b[idx + 1], 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
union UnionMemberArrays
|
||||
{
|
||||
struct { char a[4], b[4]; } a;
|
||||
struct { char a[8]; } c;
|
||||
};
|
||||
|
||||
const union UnionMemberArrays cu = {
|
||||
{ { '1', '2', '3', '4' }, { '5', } }
|
||||
};
|
||||
|
||||
static void test_const_union_member_arrays (void)
|
||||
{
|
||||
A (cu.a.a, 5);
|
||||
A (cu.a.b, 1);
|
||||
A (cu.c.a, 5);
|
||||
|
||||
const union UnionMemberArrays clu = {
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } }
|
||||
};
|
||||
|
||||
A (clu.a.a, 6);
|
||||
A (clu.a.b, 2);
|
||||
A (clu.c.a, 6);
|
||||
}
|
||||
|
||||
|
||||
union UnionMemberArrays vu = {
|
||||
{ { '1', '2', '3', '4' }, { '5', '6' } }
|
||||
};
|
||||
|
||||
static void test_nonconst_union_member_arrays (void)
|
||||
{
|
||||
A (vu.a.a, 6);
|
||||
A (vu.a.b, 2);
|
||||
A (vu.c.a, 6);
|
||||
|
||||
union UnionMemberArrays lvu = {
|
||||
{ { '1', '2', '3', '4' }, { '5', '6', '7' } }
|
||||
};
|
||||
|
||||
A (lvu.a.a, 7);
|
||||
A (lvu.a.b, 3);
|
||||
A (lvu.c.a, 7);
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
test_const_global_arrays ();
|
||||
test_const_local_arrays ();
|
||||
|
||||
test_nonconst_global_arrays ();
|
||||
test_nonconst_local_arrays ();
|
||||
|
||||
test_const_global_member_arrays ();
|
||||
test_const_local_member_arrays ();
|
||||
|
||||
test_nonconst_global_member_arrays ();
|
||||
test_nonconst_local_member_arrays ();
|
||||
|
||||
test_const_union_member_arrays ();
|
||||
test_nonconst_union_member_arrays ();
|
||||
|
||||
if (nfails)
|
||||
__builtin_abort ();
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/* Test to verify that strlen() calls with conditional expressions
|
||||
and unterminated arrays or pointers to such things as arguments
|
||||
are evaluated without making assumptions about array sizes. */
|
||||
|
||||
extern __SIZE_TYPE__ strlen (const char *);
|
||||
|
||||
unsigned nfails;
|
||||
|
||||
#define A(expr, N) \
|
||||
do { \
|
||||
const char *_s = (expr); \
|
||||
unsigned _n = strlen (_s); \
|
||||
((_n == N) \
|
||||
? 0 \
|
||||
: (__builtin_printf ("line %i: strlen ((%s) = (\"%s\"))" \
|
||||
" == %u failed\n", \
|
||||
__LINE__, #expr, _s, N), \
|
||||
++nfails)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
volatile int i0 = 0;
|
||||
|
||||
const char ca[2][3] = { "12" };
|
||||
const char cb[2][3] = { { '1', '2', '3', }, { '4' } };
|
||||
|
||||
char va[2][3] = { "123" };
|
||||
char vb[2][3] = { { '1', '2', '3', }, { '4', '5' } };
|
||||
|
||||
const char *s = "123456";
|
||||
|
||||
|
||||
static void test_binary_cond_expr_global (void)
|
||||
{
|
||||
A (i0 ? "1" : ca[0], 2);
|
||||
A (i0 ? ca[0] : "123", 3);
|
||||
|
||||
/* The call to strlen (cb[0]) is strictly undefined because the array
|
||||
isn't nul-terminated. This test verifies that the strlen range
|
||||
optimization doesn't assume that the argument is necessarily nul
|
||||
terminated.
|
||||
Ditto for strlen (vb[0]). */
|
||||
A (i0 ? "1" : cb[0], 4); /* GCC 8.2 failure */
|
||||
A (i0 ? cb[0] : "12", 2);
|
||||
|
||||
A (i0 ? "1" : va[0], 3); /* GCC 8.2 failure */
|
||||
A (i0 ? va[0] : "1234", 4);
|
||||
|
||||
A (i0 ? "1" : vb[0], 5); /* GCC 8.2 failure */
|
||||
A (i0 ? vb[0] : "12", 2);
|
||||
}
|
||||
|
||||
|
||||
static void test_binary_cond_expr_local (void)
|
||||
{
|
||||
const char lca[2][3] = { "12" };
|
||||
const char lcb[2][3] = { { '1', '2', '3', }, { '4' } };
|
||||
|
||||
char lva[2][3] = { "123" };
|
||||
char lvb[2][3] = { { '1', '2', '3', }, { '4', '5' } };
|
||||
|
||||
/* Also undefined as above. */
|
||||
A (i0 ? "1" : lca[0], 2);
|
||||
A (i0 ? lca[0] : "123", 3);
|
||||
|
||||
A (i0 ? "1" : lcb[0], 4); /* GCC 8.2 failure */
|
||||
A (i0 ? lcb[0] : "12", 2);
|
||||
|
||||
A (i0 ? "1" : lva[0], 3); /* GCC 8.2 failure */
|
||||
A (i0 ? lva[0] : "1234", 4);
|
||||
|
||||
A (i0 ? "1" : lvb[0], 5); /* GCC 8.2 failure */
|
||||
A (i0 ? lvb[0] : "12", 2);
|
||||
}
|
||||
|
||||
|
||||
static void test_ternary_cond_expr (void)
|
||||
{
|
||||
/* Also undefined. */
|
||||
A (i0 == 0 ? s : i0 == 1 ? vb[0] : "123", 6);
|
||||
A (i0 == 0 ? vb[0] : i0 == 1 ? s : "123", 5);
|
||||
A (i0 == 0 ? "123" : i0 == 1 ? s : vb[0], 3);
|
||||
}
|
||||
|
||||
|
||||
const char (*pca)[3] = &ca[0];
|
||||
const char (*pcb)[3] = &cb[0];
|
||||
|
||||
char (*pva)[3] = &va[0];
|
||||
char (*pvb)[3] = &vb[0];
|
||||
|
||||
static void test_binary_cond_expr_arrayptr (void)
|
||||
{
|
||||
/* Also undefined. */
|
||||
A (i0 ? *pca : *pcb, 4); /* GCC 8.2 failure */
|
||||
A (i0 ? *pcb : *pca, 2);
|
||||
|
||||
A (i0 ? *pva : *pvb, 5); /* GCC 8.2 failure */
|
||||
A (i0 ? *pvb : *pva, 3);
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
test_binary_cond_expr_global ();
|
||||
test_binary_cond_expr_local ();
|
||||
|
||||
test_ternary_cond_expr ();
|
||||
test_binary_cond_expr_arrayptr ();
|
||||
|
||||
if (nfails)
|
||||
__builtin_abort ();
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* Test to verify that a strlen() call with a pointer to a dynamic type
|
||||
doesn't make assumptions based on the static type of the original
|
||||
pointer. See g++.dg/init/strlen.C for the corresponding C++ test. */
|
||||
|
||||
struct A { int i; char a[1]; void (*p)(); };
|
||||
struct B { char a[sizeof (struct A) - __builtin_offsetof (struct A, a)]; };
|
||||
|
||||
__attribute__ ((noipa)) void
|
||||
init (char *d, const char *s)
|
||||
{
|
||||
__builtin_strcpy (d, s);
|
||||
}
|
||||
|
||||
struct B b;
|
||||
|
||||
__attribute__ ((noipa)) void
|
||||
test_dynamic_type (struct A *p)
|
||||
{
|
||||
/* The following call is undefined because it writes past the end
|
||||
of the p->a subobject, but the corresponding GIMPLE considers
|
||||
it valid and there's apparently no way to distinguish invalid
|
||||
cases from ones like it that might be valid. If/when GIMPLE
|
||||
changes to make this possible this test can be removed. */
|
||||
char *q = (char*)__builtin_memcpy (p->a, &b, sizeof b);
|
||||
|
||||
init (q, "foobar");
|
||||
|
||||
if (6 != __builtin_strlen (q))
|
||||
__builtin_abort();
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
struct A *p = (struct A*)__builtin_malloc (sizeof *p);
|
||||
test_dynamic_type (p);
|
||||
return 0;
|
||||
}
|
|
@ -9,23 +9,6 @@ extern char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
|
|||
extern char a0[0]; /* Intentionally not tested here. */
|
||||
extern char ax[]; /* Same. */
|
||||
|
||||
struct MemArrays {
|
||||
char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
|
||||
char a0[0]; /* Not tested here. */
|
||||
};
|
||||
|
||||
struct NestedMemArrays {
|
||||
struct { char a7[7]; } ma7;
|
||||
struct { char a6[6]; } ma6;
|
||||
struct { char a5[5]; } ma5;
|
||||
struct { char a4[4]; } ma4;
|
||||
struct { char a3[3]; } ma3;
|
||||
struct { char a2[2]; } ma2;
|
||||
struct { char a1[1]; } ma1;
|
||||
struct { char a0[0]; } ma0;
|
||||
char last;
|
||||
};
|
||||
|
||||
extern void failure_on_line (int);
|
||||
|
||||
#define TEST_FAIL(line) \
|
||||
|
@ -51,36 +34,4 @@ void test_array (void)
|
|||
T (strlen (a1) == 0); */
|
||||
}
|
||||
|
||||
void test_memarray (struct MemArrays *ma)
|
||||
{
|
||||
T (strlen (ma->a7) < sizeof ma->a7);
|
||||
T (strlen (ma->a6) < sizeof ma->a6);
|
||||
T (strlen (ma->a5) < sizeof ma->a5);
|
||||
T (strlen (ma->a4) < sizeof ma->a4);
|
||||
T (strlen (ma->a3) < sizeof ma->a3);
|
||||
|
||||
/* The following two calls are folded too early which defeats
|
||||
the strlen() optimization.
|
||||
T (strlen (ma->a2) == 1);
|
||||
T (strlen (ma->a1) == 0); */
|
||||
}
|
||||
|
||||
/* Verify that the range of strlen(A) of a last struct member is
|
||||
set even when the array is the sole member of a struct as long
|
||||
as the struct itself is a member of another struct. The converse
|
||||
is tested in stlenopt-37.c. */
|
||||
void test_nested_memarray (struct NestedMemArrays *ma)
|
||||
{
|
||||
T (strlen (ma->ma7.a7) < sizeof ma->ma7.a7);
|
||||
T (strlen (ma->ma6.a6) < sizeof ma->ma6.a6);
|
||||
T (strlen (ma->ma5.a5) < sizeof ma->ma5.a5);
|
||||
T (strlen (ma->ma4.a4) < sizeof ma->ma4.a4);
|
||||
T (strlen (ma->ma3.a3) < sizeof ma->ma3.a3);
|
||||
|
||||
/* The following two calls are folded too early which defeats
|
||||
the strlen() optimization.
|
||||
T (strlen (ma->ma2.a2) == 1);
|
||||
T (strlen (ma->ma1.a1) == 0); */
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "failure_on_line" "optimized" } } */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Test to verify that strnlen built-in expansion works correctly
|
||||
in the absence of tree strlen optimization.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
|
||||
{ dg-options "-O2 -Wall -Wno-stringop-overflow -fdump-tree-optimized" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
|
@ -85,19 +85,19 @@ void elim_strnlen_arr_cst (void)
|
|||
ELIM (strnlen (a3_7[0], 1) < 2);
|
||||
ELIM (strnlen (a3_7[0], 2) < 3);
|
||||
ELIM (strnlen (a3_7[0], 3) < 4);
|
||||
ELIM (strnlen (a3_7[0], 9) < 8);
|
||||
ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 8);
|
||||
ELIM (strnlen (a3_7[0], SIZE_MAX) < 8);
|
||||
ELIM (strnlen (a3_7[0], -1) < 8);
|
||||
ELIM (strnlen (a3_7[0], 9) <= 9);
|
||||
ELIM (strnlen (a3_7[0], PTRDIFF_MAX) <= sizeof a3_7);
|
||||
ELIM (strnlen (a3_7[0], SIZE_MAX) <= sizeof a3_7);
|
||||
ELIM (strnlen (a3_7[0], -1) <= sizeof a3_7);
|
||||
|
||||
ELIM (strnlen (a3_7[2], 0) == 0);
|
||||
ELIM (strnlen (a3_7[2], 1) < 2);
|
||||
ELIM (strnlen (a3_7[2], 2) < 3);
|
||||
ELIM (strnlen (a3_7[2], 3) < 4);
|
||||
ELIM (strnlen (a3_7[2], 9) < 8);
|
||||
ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 8);
|
||||
ELIM (strnlen (a3_7[2], SIZE_MAX) < 8);
|
||||
ELIM (strnlen (a3_7[2], -1) < 8);
|
||||
ELIM (strnlen (a3_7[2], 9) <= 9);
|
||||
ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < sizeof a3_7);
|
||||
ELIM (strnlen (a3_7[2], SIZE_MAX) < sizeof a3_7);
|
||||
ELIM (strnlen (a3_7[2], -1) < sizeof a3_7);
|
||||
|
||||
ELIM (strnlen ((char*)a3_7, 0) == 0);
|
||||
ELIM (strnlen ((char*)a3_7, 1) < 2);
|
||||
|
@ -105,123 +105,19 @@ void elim_strnlen_arr_cst (void)
|
|||
ELIM (strnlen ((char*)a3_7, 3) < 4);
|
||||
ELIM (strnlen ((char*)a3_7, 9) < 10);
|
||||
ELIM (strnlen ((char*)a3_7, 19) < 20);
|
||||
ELIM (strnlen ((char*)a3_7, 21) < 22);
|
||||
ELIM (strnlen ((char*)a3_7, 23) < 22);
|
||||
ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) < 22);
|
||||
ELIM (strnlen ((char*)a3_7, SIZE_MAX) < 22);
|
||||
ELIM (strnlen ((char*)a3_7, -1) < 22);
|
||||
ELIM (strnlen ((char*)a3_7, 21) <= sizeof a3_7);
|
||||
ELIM (strnlen ((char*)a3_7, 23) <= sizeof a3_7);
|
||||
ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) <= sizeof a3_7);
|
||||
ELIM (strnlen ((char*)a3_7, SIZE_MAX) <= sizeof a3_7);
|
||||
ELIM (strnlen ((char*)a3_7, -1) <= sizeof a3_7);
|
||||
|
||||
ELIM (strnlen (ax, 0) == 0);
|
||||
ELIM (strnlen (ax, 1) < 2);
|
||||
ELIM (strnlen (ax, 2) < 3);
|
||||
ELIM (strnlen (ax, 9) < 10);
|
||||
ELIM (strnlen (a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
|
||||
ELIM (strnlen (a3, SIZE_MAX) < PTRDIFF_MAX);
|
||||
ELIM (strnlen (a3, -1) < PTRDIFF_MAX);
|
||||
}
|
||||
|
||||
struct MemArrays
|
||||
{
|
||||
char c;
|
||||
char a0[0];
|
||||
char a1[1];
|
||||
char a3[3];
|
||||
char a5[5];
|
||||
char a3_7[3][7];
|
||||
char ax[1];
|
||||
};
|
||||
|
||||
void elim_strnlen_memarr_cst (struct MemArrays *p, int i)
|
||||
{
|
||||
ELIM (strnlen (&p->c, 0) == 0);
|
||||
ELIM (strnlen (&p->c, 1) < 2);
|
||||
ELIM (strnlen (&p->c, 9) == 0);
|
||||
ELIM (strnlen (&p->c, PTRDIFF_MAX) == 0);
|
||||
ELIM (strnlen (&p->c, SIZE_MAX) == 0);
|
||||
ELIM (strnlen (&p->c, -1) == 0);
|
||||
|
||||
/* Other accesses to internal zero-length arrays are undefined. */
|
||||
ELIM (strnlen (p->a0, 0) == 0);
|
||||
|
||||
ELIM (strnlen (p->a1, 0) == 0);
|
||||
ELIM (strnlen (p->a1, 1) < 2);
|
||||
ELIM (strnlen (p->a1, 9) == 0);
|
||||
ELIM (strnlen (p->a1, PTRDIFF_MAX) == 0);
|
||||
ELIM (strnlen (p->a1, SIZE_MAX) == 0);
|
||||
ELIM (strnlen (p->a1, -1) == 0);
|
||||
|
||||
ELIM (strnlen (p->a3, 0) == 0);
|
||||
ELIM (strnlen (p->a3, 1) < 2);
|
||||
ELIM (strnlen (p->a3, 2) < 3);
|
||||
ELIM (strnlen (p->a3, 3) < 4);
|
||||
ELIM (strnlen (p->a3, 9) < 4);
|
||||
ELIM (strnlen (p->a3, PTRDIFF_MAX) < 4);
|
||||
ELIM (strnlen (p->a3, SIZE_MAX) < 4);
|
||||
ELIM (strnlen (p->a3, -1) < 4);
|
||||
|
||||
ELIM (strnlen (p[i].a3, 0) == 0);
|
||||
ELIM (strnlen (p[i].a3, 1) < 2);
|
||||
ELIM (strnlen (p[i].a3, 2) < 3);
|
||||
ELIM (strnlen (p[i].a3, 3) < 4);
|
||||
ELIM (strnlen (p[i].a3, 9) < 4);
|
||||
ELIM (strnlen (p[i].a3, PTRDIFF_MAX) < 4);
|
||||
ELIM (strnlen (p[i].a3, SIZE_MAX) < 4);
|
||||
ELIM (strnlen (p[i].a3, -1) < 4);
|
||||
|
||||
ELIM (strnlen (p->a3_7[0], 0) == 0);
|
||||
ELIM (strnlen (p->a3_7[0], 1) < 2);
|
||||
ELIM (strnlen (p->a3_7[0], 2) < 3);
|
||||
ELIM (strnlen (p->a3_7[0], 3) < 4);
|
||||
ELIM (strnlen (p->a3_7[0], 9) < 8);
|
||||
ELIM (strnlen (p->a3_7[0], PTRDIFF_MAX) < 8);
|
||||
ELIM (strnlen (p->a3_7[0], SIZE_MAX) < 8);
|
||||
ELIM (strnlen (p->a3_7[0], -1) < 8);
|
||||
|
||||
ELIM (strnlen (p->a3_7[2], 0) == 0);
|
||||
ELIM (strnlen (p->a3_7[2], 1) < 2);
|
||||
ELIM (strnlen (p->a3_7[2], 2) < 3);
|
||||
ELIM (strnlen (p->a3_7[2], 3) < 4);
|
||||
ELIM (strnlen (p->a3_7[2], 9) < 8);
|
||||
ELIM (strnlen (p->a3_7[2], PTRDIFF_MAX) < 8);
|
||||
ELIM (strnlen (p->a3_7[2], SIZE_MAX) < 8);
|
||||
ELIM (strnlen (p->a3_7[2], -1) < 8);
|
||||
|
||||
ELIM (strnlen (p->a3_7[i], 0) == 0);
|
||||
ELIM (strnlen (p->a3_7[i], 1) < 2);
|
||||
ELIM (strnlen (p->a3_7[i], 2) < 3);
|
||||
ELIM (strnlen (p->a3_7[i], 3) < 4);
|
||||
|
||||
#if 0
|
||||
/* This is tranformed into strnlen ((char*)p + offsetof (a3_7[i]), N)
|
||||
which makes it impssible to determine the size of the array. */
|
||||
ELIM (strnlen (p->a3_7[i], 9) < 8);
|
||||
ELIM (strnlen (p->a3_7[i], PTRDIFF_MAX) < 8);
|
||||
ELIM (strnlen (p->a3_7[i], SIZE_MAX) < 8);
|
||||
ELIM (strnlen (p->a3_7[i], -1) < 8);
|
||||
#else
|
||||
ELIM (strnlen (p->a3_7[i], 9) < 10);
|
||||
ELIM (strnlen (p->a3_7[i], 19) < 20);
|
||||
#endif
|
||||
|
||||
ELIM (strnlen ((char*)p->a3_7, 0) == 0);
|
||||
ELIM (strnlen ((char*)p->a3_7, 1) < 2);
|
||||
ELIM (strnlen ((char*)p->a3_7, 2) < 3);
|
||||
ELIM (strnlen ((char*)p->a3_7, 3) < 4);
|
||||
ELIM (strnlen ((char*)p->a3_7, 9) < 10);
|
||||
ELIM (strnlen ((char*)p->a3_7, 19) < 20);
|
||||
ELIM (strnlen ((char*)p->a3_7, 21) < 22);
|
||||
ELIM (strnlen ((char*)p->a3_7, 23) < 22);
|
||||
ELIM (strnlen ((char*)p->a3_7, PTRDIFF_MAX) < 22);
|
||||
ELIM (strnlen ((char*)p->a3_7, SIZE_MAX) < 22);
|
||||
ELIM (strnlen ((char*)p->a3_7, -1) < 22);
|
||||
|
||||
ELIM (strnlen (p->ax, 0) == 0);
|
||||
ELIM (strnlen (p->ax, 1) < 2);
|
||||
ELIM (strnlen (p->ax, 2) < 3);
|
||||
ELIM (strnlen (p->ax, 9) < 10);
|
||||
ELIM (strnlen (p->a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
|
||||
ELIM (strnlen (p->a3, SIZE_MAX) < PTRDIFF_MAX);
|
||||
ELIM (strnlen (p->a3, -1) < PTRDIFF_MAX);
|
||||
ELIM (strnlen (ax, PTRDIFF_MAX) < PTRDIFF_MAX);
|
||||
ELIM (strnlen (ax, SIZE_MAX) < PTRDIFF_MAX);
|
||||
ELIM (strnlen (ax, -1) < PTRDIFF_MAX);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1121,67 +1121,23 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
|
|||
update_stmt (last.stmt);
|
||||
}
|
||||
|
||||
/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
|
||||
SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
|
||||
a character array A[N] with unknown length bounded by N, and for
|
||||
strnlen(), by min (N, BOUND). */
|
||||
/* For an LHS that is an SSA_NAME that is the result of a strlen()
|
||||
call, or when BOUND is non-null, of a strnlen() call, set LHS
|
||||
range info to [0, min (MAX, BOUND)] when the range includes more
|
||||
than one value and return LHS. Otherwise, when the range
|
||||
[MIN, MAX] is such that MIN == MAX, return the tree representation
|
||||
of (MIN). The latter allows callers to fold suitable strnlen() calls
|
||||
to constants. */
|
||||
|
||||
static tree
|
||||
maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
||||
tree
|
||||
set_strlen_range (tree lhs, wide_int max, tree bound /* = NULL_TREE */)
|
||||
{
|
||||
if (TREE_CODE (lhs) != SSA_NAME
|
||||
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
||||
return NULL_TREE;
|
||||
|
||||
if (TREE_CODE (src) == SSA_NAME)
|
||||
{
|
||||
gimple *def = SSA_NAME_DEF_STMT (src);
|
||||
if (is_gimple_assign (def)
|
||||
&& gimple_assign_rhs_code (def) == ADDR_EXPR)
|
||||
src = gimple_assign_rhs1 (def);
|
||||
}
|
||||
|
||||
wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
|
||||
wide_int min = wi::zero (max.get_precision ());
|
||||
|
||||
if (TREE_CODE (src) == ADDR_EXPR)
|
||||
{
|
||||
/* The last array member of a struct can be bigger than its size
|
||||
suggests if it's treated as a poor-man's flexible array member. */
|
||||
src = TREE_OPERAND (src, 0);
|
||||
bool src_is_array = TREE_CODE (TREE_TYPE (src)) == ARRAY_TYPE;
|
||||
if (src_is_array
|
||||
&& TREE_CODE (src) != MEM_REF
|
||||
&& !array_at_struct_end_p (src))
|
||||
{
|
||||
tree type = TREE_TYPE (src);
|
||||
if (tree size = TYPE_SIZE_UNIT (type))
|
||||
if (size && TREE_CODE (size) == INTEGER_CST)
|
||||
max = wi::to_wide (size);
|
||||
|
||||
/* For strlen() the upper bound above is equal to
|
||||
the longest string that can be stored in the array
|
||||
(i.e., it accounts for the terminating nul. For
|
||||
strnlen() bump up the maximum by one since the array
|
||||
need not be nul-terminated. */
|
||||
if (!bound && max != 0)
|
||||
--max;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TREE_CODE (src) == COMPONENT_REF && !src_is_array)
|
||||
src = TREE_OPERAND (src, 1);
|
||||
if (DECL_P (src))
|
||||
{
|
||||
/* Handle the unlikely case of strlen (&c) where c is some
|
||||
variable. */
|
||||
if (tree size = DECL_SIZE_UNIT (src))
|
||||
if (TREE_CODE (size) == INTEGER_CST)
|
||||
max = wi::to_wide (size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bound)
|
||||
{
|
||||
/* For strnlen, adjust MIN and MAX as necessary. If the bound
|
||||
|
@ -1205,7 +1161,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
|||
{
|
||||
/* For a bound in a known range, adjust the range determined
|
||||
above as necessary. For a bound in some anti-range or
|
||||
in an unknown range, use the range determined above. */
|
||||
in an unknown range, use the range determined by callers. */
|
||||
if (wi::ltu_p (minbound, min))
|
||||
min = minbound;
|
||||
if (wi::ltu_p (maxbound, max))
|
||||
|
@ -1221,6 +1177,79 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
|||
return lhs;
|
||||
}
|
||||
|
||||
/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
|
||||
SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
|
||||
a character array A[N] with unknown length bounded by N, and for
|
||||
strnlen(), by min (N, BOUND). */
|
||||
|
||||
static tree
|
||||
maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
||||
{
|
||||
if (TREE_CODE (lhs) != SSA_NAME
|
||||
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
||||
return NULL_TREE;
|
||||
|
||||
if (TREE_CODE (src) == SSA_NAME)
|
||||
{
|
||||
gimple *def = SSA_NAME_DEF_STMT (src);
|
||||
if (is_gimple_assign (def)
|
||||
&& gimple_assign_rhs_code (def) == ADDR_EXPR)
|
||||
src = gimple_assign_rhs1 (def);
|
||||
}
|
||||
|
||||
/* The longest string is PTRDIFF_MAX - 1 bytes including the final
|
||||
NUL so that the difference between a pointer to just past it and
|
||||
one to its beginning is positive. */
|
||||
wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2;
|
||||
|
||||
if (TREE_CODE (src) == ADDR_EXPR)
|
||||
{
|
||||
/* The last array member of a struct can be bigger than its size
|
||||
suggests if it's treated as a poor-man's flexible array member. */
|
||||
src = TREE_OPERAND (src, 0);
|
||||
if (TREE_CODE (src) != MEM_REF
|
||||
&& !array_at_struct_end_p (src))
|
||||
{
|
||||
tree type = TREE_TYPE (src);
|
||||
tree size = TYPE_SIZE_UNIT (type);
|
||||
if (size
|
||||
&& TREE_CODE (size) == INTEGER_CST
|
||||
&& !integer_zerop (size))
|
||||
{
|
||||
/* Even though such uses of strlen would be undefined,
|
||||
avoid relying on arrays of arrays in case some genius
|
||||
decides to call strlen on an unterminated array element
|
||||
that's followed by a terminated one. Likewise, avoid
|
||||
assuming that a struct array member is necessarily
|
||||
nul-terminated (the nul may be in the member that
|
||||
follows). In those cases, assume that the length
|
||||
of the string stored in such an array is bounded
|
||||
by the size of the enclosing object if one can be
|
||||
determined. */
|
||||
tree base = get_base_address (src);
|
||||
if (VAR_P (base))
|
||||
{
|
||||
if (tree size = DECL_SIZE_UNIT (base))
|
||||
if (size
|
||||
&& TREE_CODE (size) == INTEGER_CST
|
||||
&& TREE_CODE (TREE_TYPE (base)) != POINTER_TYPE)
|
||||
max = wi::to_wide (size);
|
||||
}
|
||||
}
|
||||
|
||||
/* For strlen() the upper bound above is equal to
|
||||
the longest string that can be stored in the array
|
||||
(i.e., it accounts for the terminating nul. For
|
||||
strnlen() bump up the maximum by one since the array
|
||||
need not be nul-terminated. */
|
||||
if (!bound && max != 0)
|
||||
--max;
|
||||
}
|
||||
}
|
||||
|
||||
return set_strlen_range (lhs, max, bound);
|
||||
}
|
||||
|
||||
/* Handle a strlen call. If strlen of the argument is known, replace
|
||||
the strlen call with the known value, otherwise remember that strlen
|
||||
of the argument is stored in the lhs SSA_NAME. */
|
||||
|
|
|
@ -23,5 +23,6 @@
|
|||
|
||||
extern bool is_strlen_related_p (tree, tree);
|
||||
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
|
||||
extern tree set_strlen_range (tree, wide_int, tree = NULL_TREE);
|
||||
|
||||
#endif // GCC_TREE_SSA_STRLEN_H
|
||||
|
|
Loading…
Reference in New Issue