On 8/4/20 11:23 PM, Aldy Hernandez wrote:


On 8/4/20 9:34 PM, Martin Sebor wrote:
On 8/4/20 5:33 AM, Aldy Hernandez via Gcc-patches wrote:
This patch adapts the strlen pass to use the irange API.

I wasn't able to remove the one annoying use of VR_ANTI_RANGE, because
I'm not sure what to do.  Perhaps Martin can shed some light.  The
current code has:

   else if (rng == VR_ANTI_RANGE)
    {
      wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
      if (wi::ltu_p (cntrange[1], maxobjsize))
        {
          cntrange[0] = cntrange[1] + 1;
          cntrange[1] = maxobjsize;

Suppose we have ~[10,20], won't the above set cntrange[] to [21,MAX]? Won't
this ignore the 0..9 that is part of the range?  What should we do here?

cntrange is the range of the strncpy (and strncat) bound.  It does
ignore the lower subrange but I think that's intentional because
the lower the bound the more likely the truncation, so it serves
to minimize false positives.

I didn't see any tests fail with the anti-range block disabled but
with some effort I was able to come up with one:

   char a[7];

   void f (int n)
   {
     if (n > 3)
       n = 0;

     strncpy (a, "12345678", n);   // -Wstringop-truncation
   }

The warning disappears when the anti-range handling is removed so
unless that's causing headaches for the new API I think we want to
keep it (and add the test case :)

Hi Martin.

Thanks for taking the time to respond.

On the strlen1 dump I see that the 3rd argument to strncpy above is:

   long unsigned int ~[4, 18446744071562067967]

which is a fancy way of saying:

   long unsigned int [0,3][18446744071562067967,+INF]

The second sub-range is basically [INT_MIN,+INF] for the original int N, which makes sense because N could be negative on the way in.

I don't understand the warning though:

a.c:8:5: warning: ‘__builtin_strncpy’ output truncated copying between 0 and 3 bytes from a
  string of length 8 [-Wstringop-truncation]
    8 |     __builtin_strncpy (a, "12345678", n);   // -Wstringop-truncation
       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The range of the bound to strncpy can certainly be [0,3], but it can also be [1844...,+INF] which shouldn't warn.

In a world without anti-ranges, we'd see the 2 sub-ranges above.  How would you suggest handling it?  We could nuke out the uppermost sub-range, but what if the range is [0,3][10,20]?  Perhaps remove from some arbitrary number on up?  Say...[0xf.....,+INF]?  This seems like a hack, but perhaps is what's needed???

It doesn't seem like the above source should warn.  Am I missing something?

FWIW, evrp gets a slightly more pessimistic range:

_1: long unsigned int ~[2147483648, 18446744071562067967]

it isn't until VRP1 that the range excludes [0,3]:

_1: long unsigned int ~[4, 18446744071562067967]

Whereas the ranger can get the more refined range at -O1, and without dominators. I would even venture to say it could get it at -O0, with just SSA + CFG.

I noticed that the strlen pass only runs at -O2. Perhaps we could explore running the pass for lower or no optimization levels when the ranger becomes available. Just a thought.

Aldy

Reply via email to