mirror of git://gcc.gnu.org/git/gcc.git
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>
|
2019-01-02 Martin Sebor <msebor@redhat.com>
|
||||||
Jeff Law <law@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
|
PR middle-end/88663
|
||||||
* gimple-fold.c (get_range_strlen): Update prototype to no longer
|
* gimple-fold.c (get_range_strlen): Update prototype to no longer
|
||||||
need the flexp argument.
|
need the flexp argument.
|
||||||
|
|
|
||||||
|
|
@ -3739,10 +3739,9 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the strlen() range to [0, MAXLEN]. */
|
||||||
if (tree lhs = gimple_call_lhs (stmt))
|
if (tree lhs = gimple_call_lhs (stmt))
|
||||||
if (TREE_CODE (lhs) == SSA_NAME
|
set_strlen_range (lhs, maxlen);
|
||||||
&& INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
|
||||||
set_range_info (lhs, VR_RANGE, minlen, maxlen);
|
|
||||||
|
|
||||||
return false;
|
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>
|
2019-01-02 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR testsuite/87304
|
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 a0[0]; /* Intentionally not tested here. */
|
||||||
extern char ax[]; /* Same. */
|
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);
|
extern void failure_on_line (int);
|
||||||
|
|
||||||
#define TEST_FAIL(line) \
|
#define TEST_FAIL(line) \
|
||||||
|
|
@ -51,36 +34,4 @@ void test_array (void)
|
||||||
T (strlen (a1) == 0); */
|
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" } } */
|
/* { dg-final { scan-tree-dump-not "failure_on_line" "optimized" } } */
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
Test to verify that strnlen built-in expansion works correctly
|
Test to verify that strnlen built-in expansion works correctly
|
||||||
in the absence of tree strlen optimization.
|
in the absence of tree strlen optimization.
|
||||||
{ dg-do compile }
|
{ dg-do compile }
|
||||||
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
|
{ dg-options "-O2 -Wall -Wno-stringop-overflow -fdump-tree-optimized" } */
|
||||||
|
|
||||||
#include "strlenopt.h"
|
#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], 1) < 2);
|
||||||
ELIM (strnlen (a3_7[0], 2) < 3);
|
ELIM (strnlen (a3_7[0], 2) < 3);
|
||||||
ELIM (strnlen (a3_7[0], 3) < 4);
|
ELIM (strnlen (a3_7[0], 3) < 4);
|
||||||
ELIM (strnlen (a3_7[0], 9) < 8);
|
ELIM (strnlen (a3_7[0], 9) <= 9);
|
||||||
ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 8);
|
ELIM (strnlen (a3_7[0], PTRDIFF_MAX) <= sizeof a3_7);
|
||||||
ELIM (strnlen (a3_7[0], SIZE_MAX) < 8);
|
ELIM (strnlen (a3_7[0], SIZE_MAX) <= sizeof a3_7);
|
||||||
ELIM (strnlen (a3_7[0], -1) < 8);
|
ELIM (strnlen (a3_7[0], -1) <= sizeof a3_7);
|
||||||
|
|
||||||
ELIM (strnlen (a3_7[2], 0) == 0);
|
ELIM (strnlen (a3_7[2], 0) == 0);
|
||||||
ELIM (strnlen (a3_7[2], 1) < 2);
|
ELIM (strnlen (a3_7[2], 1) < 2);
|
||||||
ELIM (strnlen (a3_7[2], 2) < 3);
|
ELIM (strnlen (a3_7[2], 2) < 3);
|
||||||
ELIM (strnlen (a3_7[2], 3) < 4);
|
ELIM (strnlen (a3_7[2], 3) < 4);
|
||||||
ELIM (strnlen (a3_7[2], 9) < 8);
|
ELIM (strnlen (a3_7[2], 9) <= 9);
|
||||||
ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 8);
|
ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < sizeof a3_7);
|
||||||
ELIM (strnlen (a3_7[2], SIZE_MAX) < 8);
|
ELIM (strnlen (a3_7[2], SIZE_MAX) < sizeof a3_7);
|
||||||
ELIM (strnlen (a3_7[2], -1) < 8);
|
ELIM (strnlen (a3_7[2], -1) < sizeof a3_7);
|
||||||
|
|
||||||
ELIM (strnlen ((char*)a3_7, 0) == 0);
|
ELIM (strnlen ((char*)a3_7, 0) == 0);
|
||||||
ELIM (strnlen ((char*)a3_7, 1) < 2);
|
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, 3) < 4);
|
||||||
ELIM (strnlen ((char*)a3_7, 9) < 10);
|
ELIM (strnlen ((char*)a3_7, 9) < 10);
|
||||||
ELIM (strnlen ((char*)a3_7, 19) < 20);
|
ELIM (strnlen ((char*)a3_7, 19) < 20);
|
||||||
ELIM (strnlen ((char*)a3_7, 21) < 22);
|
ELIM (strnlen ((char*)a3_7, 21) <= sizeof a3_7);
|
||||||
ELIM (strnlen ((char*)a3_7, 23) < 22);
|
ELIM (strnlen ((char*)a3_7, 23) <= sizeof a3_7);
|
||||||
ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) < 22);
|
ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) <= sizeof a3_7);
|
||||||
ELIM (strnlen ((char*)a3_7, SIZE_MAX) < 22);
|
ELIM (strnlen ((char*)a3_7, SIZE_MAX) <= sizeof a3_7);
|
||||||
ELIM (strnlen ((char*)a3_7, -1) < 22);
|
ELIM (strnlen ((char*)a3_7, -1) <= sizeof a3_7);
|
||||||
|
|
||||||
ELIM (strnlen (ax, 0) == 0);
|
ELIM (strnlen (ax, 0) == 0);
|
||||||
ELIM (strnlen (ax, 1) < 2);
|
ELIM (strnlen (ax, 1) < 2);
|
||||||
ELIM (strnlen (ax, 2) < 3);
|
ELIM (strnlen (ax, 2) < 3);
|
||||||
ELIM (strnlen (ax, 9) < 10);
|
ELIM (strnlen (ax, 9) < 10);
|
||||||
ELIM (strnlen (a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
|
ELIM (strnlen (ax, PTRDIFF_MAX) < PTRDIFF_MAX);
|
||||||
ELIM (strnlen (a3, SIZE_MAX) < PTRDIFF_MAX);
|
ELIM (strnlen (ax, SIZE_MAX) < PTRDIFF_MAX);
|
||||||
ELIM (strnlen (a3, -1) < PTRDIFF_MAX);
|
ELIM (strnlen (ax, -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1121,67 +1121,23 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
|
||||||
update_stmt (last.stmt);
|
update_stmt (last.stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
|
/* For an LHS that is an SSA_NAME that is the result of a strlen()
|
||||||
SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
|
call, or when BOUND is non-null, of a strnlen() call, set LHS
|
||||||
a character array A[N] with unknown length bounded by N, and for
|
range info to [0, min (MAX, BOUND)] when the range includes more
|
||||||
strnlen(), by min (N, BOUND). */
|
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
|
tree
|
||||||
maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
set_strlen_range (tree lhs, wide_int max, tree bound /* = NULL_TREE */)
|
||||||
{
|
{
|
||||||
if (TREE_CODE (lhs) != SSA_NAME
|
if (TREE_CODE (lhs) != SSA_NAME
|
||||||
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
||||||
return NULL_TREE;
|
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 ());
|
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)
|
if (bound)
|
||||||
{
|
{
|
||||||
/* For strnlen, adjust MIN and MAX as necessary. If the 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
|
/* For a bound in a known range, adjust the range determined
|
||||||
above as necessary. For a bound in some anti-range or
|
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))
|
if (wi::ltu_p (minbound, min))
|
||||||
min = minbound;
|
min = minbound;
|
||||||
if (wi::ltu_p (maxbound, max))
|
if (wi::ltu_p (maxbound, max))
|
||||||
|
|
@ -1221,6 +1177,79 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
||||||
return lhs;
|
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
|
/* Handle a strlen call. If strlen of the argument is known, replace
|
||||||
the strlen call with the known value, otherwise remember that strlen
|
the strlen call with the known value, otherwise remember that strlen
|
||||||
of the argument is stored in the lhs SSA_NAME. */
|
of the argument is stored in the lhs SSA_NAME. */
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,6 @@
|
||||||
|
|
||||||
extern bool is_strlen_related_p (tree, tree);
|
extern bool is_strlen_related_p (tree, tree);
|
||||||
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, 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
|
#endif // GCC_TREE_SSA_STRLEN_H
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue