This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] handle pathological anti-ranges in gimple_fold_builtin_memory_op (PR 81908)
- From: Jeff Law <law at redhat dot com>
- To: Martin Sebor <msebor at gmail dot com>, Richard Biener <richard dot guenther at gmail dot com>
- Cc: Gcc Patch List <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 24 Aug 2017 15:52:41 -0600
- Subject: Re: [PATCH] handle pathological anti-ranges in gimple_fold_builtin_memory_op (PR 81908)
- Authentication-results: sourceware.org; auth=none
- Authentication-results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com
- Authentication-results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=law at redhat dot com
- Dmarc-filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4D8B9883CE
- References: <fdd45b8d-876d-0639-34d2-96af298a44d4@gmail.com> <CAFiYyc0yuKcYU92=YEKxTn-gQJue+OPCKqOMrRgG2L9wnPgG6g@mail.gmail.com> <9143b5b4-e410-1c21-91e9-aa2a91b5ceeb@gmail.com>
On 08/24/2017 09:03 AM, Martin Sebor wrote:
> On 08/24/2017 08:03 AM, Richard Biener wrote:
>> On Wed, Aug 23, 2017 at 9:42 PM, Martin Sebor <msebor@gmail.com> wrote:
>>> Bug 81908 is about a -Wstringop-overflow warning for a Fortran
>>> test triggered by a recent VRP improvement. A simple test case
>>> that approximates the warning is:
>>>
>>> void f (char *d, const char *s, size_t n)
>>> {
>>> if (n > 0 && n <= SIZE_MAX / 2)
>>> n = 0;
>>>
>>> memcpy (d, s, n); // n in ~[1, SIZE_MAX / 2]
>>> }
>>>
>>> Since the only valid value of n is zero the call to memcpy can
>>> be considered a no-op (a value of n > SIZE_MAX is in excess of
>>> the maximum size of the largest object and would surely make
>>> the call crash).
>>>
>>> The important difference between the test case and Bug 81908
>>> is that in the latter, the code is emitted by GCC itself from
>>> what appears to be correct source (looks like it's the result
>>> of the loop distribution pass). I believe the warning for
>>> the test case above and for other human-written code like it
>>> is helpful, but warning for code emitted by GCC, even if it's
>>> dead or unreachable, is obviously not (at least not to users).
>>>
>>> The attached patch enhances the gimple_fold_builtin_memory_op
>>> function to eliminate this patholohgical case by making use
>>> of range information to fold into no-ops calls to memcpy whose
>>> size argument is in a range where the only valid value is zero.
>>> This gets rid of the warning and improves the emitted code.
>>>
>>> Tested on x86_64-linux.
>>
>> @@ -646,6 +677,12 @@ gimple_fold_builtin_memory_op
>> (gimple_stmt_iterator *gsi,
>> tree destvar, srcvar;
>> location_t loc = gimple_location (stmt);
>>
>> + if (tree valid_len = only_valid_value (len))
>> + {
>> + /* LEN is in range whose only valid value is zero. */
>> + len = valid_len;
>> + }
>> +
>> /* If the LEN parameter is zero, return DEST. */
>> if (integer_zerop (len))
>>
>> just enhance this check to
>>
>> if (integer_zerop (len)
>> || size_must_be_zero_p (len))
>>
>> ? 'only_valid_value' looks too generic for this.
>
> Sure.
>
> FWIW, the reason I did it this was because my original patch
> returned error_mark_node for entirely invalid ranges and had
> the caller replace the call with a trap. I decided not to
> include that part in this fix to keep it contained.
Seems reasonable. Though I would suggest going forward with trap
replacement for clearly invalid ranges as a follow-up. Once you do trap
replacement, the input operands all become dead as does all the code
after the trap and the outgoing edges in the CFG.
That often exposes a fair amount of cleanup. Furthermore on targets
that have conditional traps, the controlling condition often turns into
a conditional trap. In all, you get a lot of nice cascading effects
when you turn something that is clearly bogus into a trap.
gimple-ssa-isolate-erroneous-paths probably has the infrastructure you
need, including a code you can crib to detect PHI arguments which would
cause bogus behavior and allow you to isolate that specific path.
>
>>
>> + if (!wi::fits_uhwi_p (min) || !wi::fits_uhwi_p (max))
>> + return NULL_TREE;
>> +
>>
>> why?
>
> Only because I never remember what APIs are safe to use with
> what input.
>
>> + if (wi::eq_p (min, wone)
>> + && wi::geu_p (max + 1, ssize_max))
>>
>> if (wi::eq_p (min, 1)
>> && wi::gtu_p (max, wi::max_value (prec, SIGNED)))
>>
>> your ssize_max isn't signed size max, and max + 1 might overflow to zero.
>
> You're right that the addition to max would be better done
> as subtraction from the result of (1 << N). Thank you.
>
> If (max + 1) overflowed then (max == TYPE_MAX) would have
> to hold which I thought could never be true for an anti
> range. (The patch includes tests for this case.) Was I
> wrong?
Couldn't we have an anti range like ~[TYPE_MAX,TYPE_MAX]? Or am I
misunderstanding something.
>
> Attached is an updated version with the suggested changes
> plus an additional test to verify the absence of warnings.
The patch is OK.
I'll note this is another use of anti-ranges. I'd really like to see
Aldy's work on the new range API move forward and get rid of anti-ranges.
THanks,
jeff