On 08/05/18 17:58, Jeff Law wrote:
> On 08/05/2018 12:08 AM, Bernd Edlinger wrote:
>> I see this from a software engineering POV.
>>
>> If we have code like this:
>>
>> void test (const char *x)
>> {
>>     assert (strlen (x) < 10);
>> }
>>
>> One would usually expect the program to abort (or at least abort with
>> a near 100% likelihood) if x is not a valid string with length less
>> than 10.
> I would not expect the program to abort if this function were called
> with an invalid (ie unterminated) string.  In that scenario I know
> enough to not expect anything because my program is broken, plain and
> simple.
> 
>>
>> But if lto and other optimizations show that this code is invoked with
>> an invalid, non-zero terminated string the assertion is suddenly gone.
> And the program is invalid as it exhibits undefined behavior.  One
> undefined behavior is exhibited I have no expectations.  I *like* when
> we do something like trap as soon as undefined behavior is discovered,
> but I do not expect it.
> 
>>
>> Martin, why do you insist that GCC has to do this, and that it must
>> be a good idea to do so, just based on the language definition?
> We do this all the time in all kinds of situations.
> 
> The language definition provides the contract that the programmer and
> compiler must adhere to.  When the contract is broken we can not be
> responsible for the resulting code as the input source is simply broken.
> 
>>
>> Why do we need assertions at all, when all programs have to be completely
>> correct before we may compile them?
> That's what compilers do.  When they see code that is pointless it gets
> removed.  As engineers we sometimes say "while this is undefined
> behavior we're not going to exploit the undefined-ness".  That is based
> on our experience as developers.  And sometimes we may not even agree
> where the line between optimize this vs do not because it's going to
> surprise a developer.
> 

Sorry, to re-iterate on this topic, but maybe this can give some insights.

I'd say, my concern would be resolved if strlen range information
would not be more aggressive than the well-known loop-niter optimization.

What I mean, if strlen would be defined like an inline macro, the assertion
does not get optimized, even if the function is later in-lined in a totally
different context:


#define strlen(x) ({ int _l; for (_l=0; (x)[_l]; _l++); _l;})
void test (const char *x)
{
     assert (strlen (x) < 10);
}


But it would get optimized, when x is declared locally.
The rationale might be, that the type of object where x points
to is unknown at where the assertion is vs. the type
of object is statically known at where the assertion is.

What is the reason for this, and what would be necessary to get the exact
same behavior with the string range info?


Thanks
Bernd.

Reply via email to