diff --git a/gcc/testsuite/gcc.c-torture/compile/pr110603.c b/gcc/testsuite/gcc.c-torture/compile/pr110603.c new file mode 100644 index 0000000000000000000000000000000000000000..afcc1a522c234b2f909cc94678ba79cfa19e7a28 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr110603.c @@ -0,0 +1,16 @@ +/* PR tree-optimization/110603 */ + +typedef __SIZE_TYPE__ size_t; +void *memcpy (void *, const void *, size_t); +int snprintf (char *restrict, size_t, const char *restrict, ...); +extern char a[2]; +void bar (void); + +void +foo (void) +{ + memcpy (a, "12", sizeof (a)); + int b = snprintf (0, 0, "%s", a); + if (b <= 3) + bar (); +} diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc index c20db7a0cd958ca82c96ef807e822ab8480261f0..f2fd47d77e89b8831a0ce06c3cf6b0356dbe90e1 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -1228,7 +1228,6 @@ get_range_strlen_dynamic (tree src, gimple *stmt, { tree type = vr.type (); pdata->minlen = wide_int_to_tree (type, vr.lower_bound ()); - pdata->maxlen = wide_int_to_tree (type, vr.upper_bound ()); } } else @@ -1253,9 +1252,21 @@ get_range_strlen_dynamic (tree src, gimple *stmt, { ++off; /* Increment for the terminating nul. */ tree toffset = build_int_cst (size_type_node, off); - pdata->maxlen = fold_build2 (MINUS_EXPR, size_type_node, size, - toffset); - pdata->maxbound = pdata->maxlen; + pdata->maxlen = fold_build2 (MINUS_EXPR, size_type_node, + size, toffset); + if (tree_int_cst_lt (pdata->maxlen, pdata->minlen)) + /* This can happen when triggering UB, when base is an + array which is known to be filled with at least size + non-zero bytes. E.g. for + char a[2]; memcpy (a, "12", sizeof a); + We don't want to create an invalid range [2, 1] + where 2 comes from the number of non-zero bytes and + 1 from longest valid zero-terminated string that can + be stored in such an array, so pick just one of + those, pdata->minlen. See PR110603. */ + pdata->maxlen = build_all_ones_cst (size_type_node); + else + pdata->maxbound = pdata->maxlen; } else pdata->maxlen = build_all_ones_cst (size_type_node);