Assert and undefined behavior
Jonathan M Davis
newsgroup.d at jmdavisprog.com
Fri Oct 13 19:13:09 UTC 2017
On Friday, October 13, 2017 11:26:54 kdevel via Digitalmars-d-learn wrote:
> On Friday, 13 October 2017 at 02:22:24 UTC, Jonathan M Davis
>
> wrote:
> > You've told it that i should never be 3 at that point and that
> > it's a bug if it is, and as such, it is free to assume that i
> > is never 3 after the assertion even if the assertion is
> > compiled out with -release - that is the only place that
> > undefined behavior may enter into it.
>
> Thanks for the clarification! This is a difference to C where
> assert has only a diagnostic purpose. Disabling assertions in C
> (by setting NDEBUG) does AFAICS neither introduce undefined
> behavior nor is the compiler entitled to optimize code away based
> on the assertion. This C program
>
> --- test.c
> #include <stdio.h>
> #define NDEBUG 1
> #include <assert.h>
> int main ()
> {
> int i = 3;
> assert (i != 3);
> if (i == 3)
> printf ("%d\n", i);
> return 0;
> }
> ---
>
> is IMHO conforming and it is defined to print 3 in a conforming
> environment. The 'corresponding' D program
>
> --- assert4.d
> import std.stdio;
> int main ()
> {
> int i = 3;
> assert (i != 3);
> if (i == 3)
> writef ("%d\n", i);
> return 0;
> }
> ---
>
> is 'conforming' (but buggy) under non-release-D and
> 'non-conforming' (because of the undefined behavior) otherwise.
> Is this judgement correct?
Essentially, though talking about conforming usually has to do with spec.
In both C/C++ and D, if you use an assertion, you're saying that if the
assertion fails, then the logic in your code is faulty, and there is a bug
in your program. With C/C++, it may not be codified that the compiler
understands that, but the meaning is the same. If the assertion is compiled
out but would have failed, then your program is in an invalid state and will
do who-knows-what. By definition, you're screwed. Your program is doing
something that you have said should never happen. How screwed you actually
are can vary considerably, and if all it does is print out the value and
never use it again, then you're not very screwed, but that also means that
it was a rather odd assertion (though you're obviously doing that here as an
example and not something that someone would normally do).
Because D's compiler does understand what assert means, it is allowed to
optimize based on that fact. So, it _can_ generate code based on the
assumption that the assertion succeeded, which can increase how screwed you
are if the assertion is compiled out but would have failed, but your program
is in an invalid state either way, because you've asserted that something is
true when it isn't and thus indicated that if it isn't true, there is a bug
in your program, and its logic is wrong. And as soon as the logic in your
program is wrong, then it's not going to behave correctly. It's just a
question of how badly behaved it will be.
So, we can talk about the behavior being undefined if the assertion would
have failed on the basis that the compiler could generate optimized code
that assumes that the assertion succeeded and thus do weirder things than it
would have done if the code hadn't been optimized that way, but as far as
the language is concerned, it's undefined behavior due to the simple fact
that you've asserted that something is true which isn't. You yourself have
stated that something must be true for your program to be valid, and it
isn't true.
As long as the assertions are compiled in, then the fact that the logic in
your program was invalid is caught, whereas if they're not compiled in, then
it's not caught. But if the asserted condition is false, then your program
is wrong either way.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list