www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - The case of -debug -O and: is breaking pure/ nogc/nothrow/ safe UB

reply Guillaume Piolat <first.last gmail.com> writes:
The D specification says:

"A ConditionalStatement that has a DebugCondition is called a 
DebugStatement. DebugStatements have relaxed semantic checks in 
that pure,  nogc, nothrow and  safe checks are not done. Neither 
do DebugStatements influence the inference of pure,  nogc, 
nothrow and  safe attributes."


So it seems under a debug clause you don't have to conform to 
pure/ nogc/nothrow/ safe.

The immediate question that follow is:

"Is breaking pure/ nogc/nothrow/ safe Undefined Behaviour (UB) in 
a DebugStatement?"

Would the optimizer -O breaks code that breaks such by virtue of 
being -debug?

If no (not UB), doesn't this guarantees that no optimizations 
will ever be performed thanks to pure/ nogc/nothrow/ safe?
Apr 18 2018
next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 18 April 2018 at 13:15:08 UTC, Guillaume Piolat 
wrote:
 The D specification says:

 "A ConditionalStatement that has a DebugCondition is called a 
 DebugStatement. DebugStatements have relaxed semantic checks in 
 that pure,  nogc, nothrow and  safe checks are not done. 
 Neither do DebugStatements influence the inference of pure, 
  nogc, nothrow and  safe attributes."


 So it seems under a debug clause you don't have to conform to 
 pure/ nogc/nothrow/ safe.
Correct. Good luck trying to debug a pure function if you can't print intermediates.
 The immediate question that follow is:

 "Is breaking pure/ nogc/nothrow/ safe Undefined Behaviour (UB) 
 in a DebugStatement?"
Pure: definitely no, debug escaping pure is pretty much the whole point. nogc/nothrow/ safe I'm not so sure about. I think it is allowed because logging functions may not necessarily be nogc/nothrow/ safe and not being able to call them defeats the purpose of debug.
 Would the optimizer -O breaks code that breaks such by virtue 
 of being -debug?
I don't think so: pure: optimisations are about eliding calls with identical arguments. You shouldn't be relying on any variations due to optimisation nogc: no optimisation are performed based on this knowledge. nothrow: optimisations are about eliding unwinding tables, I don't think this would have an effect on the soundness of the function. safe: debug is effectively trusted, the usual rules apply.
Apr 18 2018
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, April 18, 2018 13:15:08 Guillaume Piolat via Digitalmars-d-
learn wrote:
 The D specification says:

 "A ConditionalStatement that has a DebugCondition is called a
 DebugStatement. DebugStatements have relaxed semantic checks in
 that pure,  nogc, nothrow and  safe checks are not done. Neither
 do DebugStatements influence the inference of pure,  nogc,
 nothrow and  safe attributes."


 So it seems under a debug clause you don't have to conform to
 pure/ nogc/nothrow/ safe.

 The immediate question that follow is:

 "Is breaking pure/ nogc/nothrow/ safe Undefined Behaviour (UB) in
 a DebugStatement?"

 Would the optimizer -O breaks code that breaks such by virtue of
 being -debug?

 If no (not UB), doesn't this guarantees that no optimizations
 will ever be performed thanks to pure/ nogc/nothrow/ safe?
It wouldn't surprise me if Walter were the only person who could really answer that, though maybe one of the other compiler devs could. However, I'm quite sure that if you have strongly pure function, and you've turned on optimizations, extra calls to it will be elided regardless of the function internals, because that decision is made based on the function signature. The same will go for any optimization that is done based on the function signature. nothrow, for instance, would cause problems. If the function is nothrow, the compiler will have omitted all of the exception handling code around the function call, so if an exception is somehow thrown from a nothrow function, it's likely to cause some unpleasant problems. I expect that it will work on some level, since you can throw Errors from nothrow functions, but in the case of Errors, it's not guaranteed that any clean-up code is run (e.g. destructors and scope statements may or may not run and almost certainly won't if the function being called was nothrow, since that's the kind of thing that gets removed from around calls to nothrow functions when optimizing code). So, an Exception being thrown from a nothrow function would be very similar to an Error being thrown from a nothrow function. Either way, you don't want it to happen if it's not then going to kill your program, and while an Error is virtually guaranteed to bubble to the top and result in your program dying, in the case of an Exception, you might have something catching Exceptions which will end up catching it, in which case the program will be an invalid state, but it won't actually be killed. So, that could be very bad. I don't think that nogc matters much one way or the other unless you haven't linked in the GC (e.g. if you're using -betterC). AFAIK, _all_ nogc does is provide a way for the programmer to know for sure that a function doesn't allocate using the GC, and I don't think that it does any optimizations of any kind (I honestly don't know of any way that that information could even theoretically be used for optimizations). So, that probably doesn't matter in practice, though it wouldn't surprise me if at some point, someone figures out something clever that can be assumed based on nogc, and you end up with problems if you violate it. All that violating safe is going to do is essentially mean that you've marked a section of code as trusted. If the code in question is actually safe but just couldn't be verified as such by the compiler, then you're fine, but if it's actually doing something that isn't safe, then you could have memory corruption problems. But that's the same with anything that's marked trusted. What I can't say for sure is what happens inside the function when it's compiled. What I expect would happen would be that inside the debug statement, any errors related to stuff like pure would be ignored but that the compiler would otherwise treat that code like any other code in the function. - Jonathan M Davis
Apr 18 2018
parent Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 18 April 2018 at 13:47:35 UTC, Jonathan M Davis 
wrote:
 <Exceptional answer>
Thanks for both your answers, Jonathan and Nicholas. To the extent that I'd like to explain this in a d-idioms post, here is a tentative synthesis of your answers (Jonathan M Davis and Nicholas Wilson): - breaking pure with -debug is UB - breaking nogc with -debug is definately not UB - breaking safe wit -debug is potentially UB, like an incorrect trusted clause would be (I'm assuming adverse conditions here) - there is disagreement between you w.r.t whether breaking nothrow with -debug is UB or not Note that I'm using the "undefined behaviour" term even though the behaviour is quite more constrained than that, because readers have a notion of what "undefined behaviour" is. For the purpose of brevity and simplicity I'll have to unify(!) this complicated situation in "breaking pure/ nogc/nothrow/ safe is Undefined Behaviour though in most cases it will work just fine".
Apr 18 2018