[PATCH] strlen: Fix handle_builtin_string_cmp [PR96758]
Richard Biener
rguenther@suse.de
Tue Aug 25 07:09:53 GMT 2020
On Mon, 24 Aug 2020, Jakub Jelinek wrote:
> Hi!
>
> The following testcase is miscompiled, because handle_builtin_string_cmp
> sees a strncmp call with constant last argument 4, where one of the strings
> has an upper bound of 5 bytes (due to it being an array of that size) and
> the other has a known string length of 1 and the result is used only in
> equality comparison.
> It is folded into __builtin_strncmp_eq (str1, str2, 4), which is
> incorrect, because that means reading 4 bytes from both strings and
> comparing that. When one of the strings has known strlen of 1, we want to
> compare just 2 bytes, not 4, as strncmp shouldn't compare any bytes beyond
> the null.
> So, the last argument to __builtin_strncmp_eq should be the minimum of the
> provided strncmp last argument and the known string length + 1 (assuming
> the other string has only a known upper bound due to array size).
>
> Besides that, I've noticed the code has been written with the intent to also
> support the case where we know exact string length of both strings (but not
> the string content, so we can't compute it at compile time). In that case,
> both cstlen1 and cstlen2 are non-negative and both arysiz1 and arysiz2 are
> negative. We wouldn't optimize that, cmpsiz would be either the strncmp
> last argument, or for strcmp the first string length, but varsiz would be
> -1 and thus cmpsiz would be never < varsiz. The patch fixes it by using the
> correct length, in that case using the minimum of the two and for strncmp
> also the last argument.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK.
> For backporting, I think we should keep the
> - if (cmpsiz < varsiz && used_only_for_zero_equality (lhs))
> + if ((varsiz < 0 || cmpsiz < varsiz) && used_only_for_zero_equality (lhs))
> change outso that we don't introduce a new optimization and just fix the
> bug.
Agreed.
Richard.
> 2020-08-24 Jakub Jelinek <jakub@redhat.com>
>
> PR tree-optimization/96758
> * tree-ssa-strlen.c (handle_builtin_string_cmp): If both cstlen1
> and cstlen2 are set, set cmpsiz to their minimum, otherwise use the
> one that is set. If bound is used and smaller than cmpsiz, set cmpsiz
> to bound. If both cstlen1 and cstlen2 are set, perform the optimization.
>
> * gcc.dg/strcmpopt_12.c: New test.
>
> --- gcc/tree-ssa-strlen.c.jj 2020-07-28 15:39:10.078755265 +0200
> +++ gcc/tree-ssa-strlen.c 2020-08-24 11:31:05.457832003 +0200
> @@ -4485,11 +4485,19 @@ handle_builtin_string_cmp (gimple_stmt_i
> ++cstlen2;
>
> /* The exact number of characters to compare. */
> - HOST_WIDE_INT cmpsiz = bound < 0 ? cstlen1 < 0 ? cstlen2 : cstlen1 : bound;
> + HOST_WIDE_INT cmpsiz;
> + if (cstlen1 >= 0 && cstlen2 >= 0)
> + cmpsiz = MIN (cstlen1, cstlen2);
> + else if (cstlen1 >= 0)
> + cmpsiz = cstlen1;
> + else
> + cmpsiz = cstlen2;
> + if (bound >= 0)
> + cmpsiz = MIN (cmpsiz, bound);
> /* The size of the array in which the unknown string is stored. */
> HOST_WIDE_INT varsiz = arysiz1 < 0 ? arysiz2 : arysiz1;
>
> - if (cmpsiz < varsiz && used_only_for_zero_equality (lhs))
> + if ((varsiz < 0 || cmpsiz < varsiz) && used_only_for_zero_equality (lhs))
> {
> /* If the known length is less than the size of the other array
> and the strcmp result is only used to test equality to zero,
> --- gcc/testsuite/gcc.dg/strcmpopt_12.c.jj 2020-08-24 11:36:21.380357549 +0200
> +++ gcc/testsuite/gcc.dg/strcmpopt_12.c 2020-08-24 11:36:35.405158915 +0200
> @@ -0,0 +1,17 @@
> +/* PR tree-optimization/96758 */
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +int v = 1;
> +
> +int
> +main ()
> +{
> + const char *s = v ? "a" : "b";
> + char x[5];
> + char y[5] = "a\0a";
> + __builtin_memcpy (x, y, sizeof (y));
> + if (__builtin_strncmp (x, s, 4) != 0)
> + __builtin_abort ();
> + return 0;
> +}
>
> Jakub
>
>
--
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
More information about the Gcc-patches
mailing list