On January 9, 2017 6:02:16 PM GMT+01:00, Jeff Law <l...@redhat.com> wrote:
>On 01/09/2017 02:36 AM, Richard Biener wrote:
>>>
>>>
>>> a = 1;
>>> <trigger non-call exception>
>>> a = 2;
>>>
>>>
>>> If "a" escapes such that its value can be queried in the exception
>handler,
>>> then the exception handler would be able to observe the first store
>and thus
>>> it should not be removed.
>>
>> Yes, and it won't as long as the EH is thrown internally (and thus we
>have
>> a CFG reflecting it).  When it's only externally catched we lose of
>course...
>>
>> We'd need an Ada testcase to actually show behavior that is not
>conforming
>> to an existing language specification though.
>I'm not versed enough in Ada to even attempt to pull together a
>testcase 
>for this.
>
>>
>> I suspect we have a similar issue in C++ for sth like
>>
>> void __attribute__((const)) foo () { throw; }
>>
>> int x;
>> void bar ()
>> {
>>   x = 1;
>>   foo ();
>>   x = 2;
>> }
>>
>> where foo is const but not nothrow.
>I wouldn't be surprised if there's other problems with const functions 
>that can throw.
>
>>
>>> We also have to be cognizant of systems where there is memory mapped
>at
>>> location 0.  When that is true, we must check pt.null and honor it,
>even if
>>> it pessimizes code.
>>
>> With -fno-delete-null-pointer-checks (that's what such systems set)
>PTA computes
>> 0 as "nonlocal" and thus it won't be a singleton points-to solution.
>Ah, good.
>
>>
>>>
>>>
>>>> For
>>>>
>>>> int foo (int *p, int b)
>>>> {
>>>>   int *q;
>>>>   int i = 1;
>>>>   if (b)
>>>>     q = &i;
>>>>   else
>>>>     q = (void *)0;
>>>>   *q = 2;
>>>>   i = 3;
>>>>   return *q;
>>>> }
>>>
>>> So on a system where *0 is a valid memory address, *q = 2 does not
>make
>>> anything dead, nor does i = 3 unless we were to isolate the
>THEN/ELSE
>>> blocks.
>>>
>>> On a system where *0 traps, there is no way to observe the value of
>"i" in
>>> the handler.  Thus i = 1 is a dead store.  I believe we must keep
>the *q = 2
>>> store because it can trigger a signal/exception which is itself an
>>> observable side effect?  Right?
>>
>> But writing to 0 invokes undefined behavior which we have no
>obligation to
>> preserve (unless we make it well-defined with -fnon-call-exceptions
>-fexceptions
>> as a GCC extension).
>It may invoke undefined behavior, but to date we have explicitly chosen
>
>to preserve the *0 = <something> to trigger a fault via the virtual 
>memory system.  We kicked this around extensively in Nov 2013 with the 
>introduction of isolation of erroneous paths.

Note we do not preserve traps with -ftrapv -fnon-call-exceptions either.  Or 
generally we happily reorder global sides effects with externally throwing 
stmts.

>I think part of what pushed us that direction was that a program could 
>catch the signal related to the NULL dereference, then do something 
>sensible in the handler.  That also happens to match what the Go 
>language requires.
>
>
>
>>
>>>>
>>>> we remove all stores but the last store to i and the load from q
>(but we
>>>> don't
>>>> replace q with &i here, a missed optimization if removing the other
>stores
>>>> is
>>>> valid).
>>>
>>> But if we remove the *q = 2 store, we remove an observable side
>effect, the
>>> trap/exception itself if we reach that statement via the ELSE path.
>>
>> As said above - I don't think we have to care for C/C++ w/o
>> -fnon-call-exceptions.
>So in the immediate term I propose we conditionalize the pt.null check 
>on non-call exceptions.  THen I'll look more closely at the example 
>above and see what we can reasonably do there.

Fix the pt-null bugs in PTA so we do not need the conservative fallback.  As 
said I have partial patches for this.

Richard.

>jeff

Reply via email to