The new get_range_strlen_dynamic function has a couple of bugs
where it assumes that the length range bounds it gets back from
get_range_strlen are non-null integer constants. The attached
"quick and dirty" fix removes those assumptions. Since it's
apparently causing package failures in Jeff's GCC buildbot
I will commit the patch on Monday to get those builds to pass.
But I'm not too happy with how fragile this seems to be so I
will try to do some further cleanup here in the near future
to make it more robust.
Martin
PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on a conditional of two strings
gcc/testsuite/ChangeLog:
PR tree-optimization/91570
* gcc.dg/pr91570.c: New test.
gcc/ChangeLog:
PR tree-optimization/91570
* tree-ssa-strlen.c (get_range_strlen_dynamic): Handle null and
non-constant maxlen and maxbound.
Index: gcc/testsuite/gcc.dg/pr91570.c
===================================================================
--- gcc/testsuite/gcc.dg/pr91570.c (nonexistent)
+++ gcc/testsuite/gcc.dg/pr91570.c (working copy)
@@ -0,0 +1,30 @@
+/* PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on
+ a conditional of two strings
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+extern char a[], b[];
+
+/* Test case from comment #0 on the bug. */
+
+void comment_0 (int i)
+{
+ a[0] = 0;
+ b[0] = '1';
+
+ const char *p = i ? b : a;
+
+ if (__builtin_snprintf (0, 0, "%s", p) < 4)
+ __builtin_abort ();
+}
+
+
+/* Test case from comment #2 on the bug. */
+
+void comment_2 (char *s)
+{
+ char *t = __builtin_strrchr (s, '/');
+ __builtin_strcat (s, ".SIF");
+ t = t ? t : s;
+ __builtin_printf ("%s", t);
+}
Index: gcc/tree-ssa-strlen.c
===================================================================
--- gcc/tree-ssa-strlen.c (revision 276021)
+++ gcc/tree-ssa-strlen.c (working copy)
@@ -896,7 +896,8 @@ get_range_strlen_dynamic (tree src, c_strlen_data
if (!argdata.minlen
|| (integer_zerop (argdata.minlen)
- && integer_all_onesp (argdata.maxbound)
+ && (!argdata.maxbound
+ || integer_all_onesp (argdata.maxbound))
&& integer_all_onesp (argdata.maxlen)))
{
/* Set the upper bound of the length to unbounded. */
@@ -910,11 +911,13 @@ get_range_strlen_dynamic (tree src, c_strlen_data
|| tree_int_cst_lt (argdata.minlen, pdata->minlen))
pdata->minlen = argdata.minlen;
if (!pdata->maxlen
- || tree_int_cst_lt (pdata->maxlen, argdata.maxlen))
+ || (argdata.maxlen
+ && tree_int_cst_lt (pdata->maxlen, argdata.maxlen)))
pdata->maxlen = argdata.maxlen;
if (!pdata->maxbound
- || (tree_int_cst_lt (pdata->maxbound,
- argdata.maxbound)
+ || (argdata.maxbound
+ && tree_int_cst_lt (pdata->maxbound,
+ argdata.maxbound)
&& !integer_all_onesp (argdata.maxbound)))
pdata->maxbound = argdata.maxbound;
}
@@ -1007,11 +1010,19 @@ get_range_strlen_dynamic (tree src, c_strlen_data
pdata->maxlen = build_all_ones_cst (size_type_node);
}
}
- else
+ else if (TREE_CODE (pdata->minlen) == INTEGER_CST)
{
pdata->maxlen = pdata->minlen;
pdata->maxbound = pdata->minlen;
}
+ else
+ {
+ /* For PDATA->MINLEN that's a non-constant expression such
+ as PLUS_EXPR whose value range is unknown, set the bounds
+ to zero and SIZE_MAX. */
+ pdata->minlen = build_zero_cst (size_type_node);
+ pdata->maxlen = build_all_ones_cst (size_type_node);
+ }
return true;
}