Assert and undefined behavior

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed Oct 11 11:04:22 UTC 2017


On Wednesday, October 11, 2017 09:27:49 John Burton via Digitalmars-d-learn 
wrote:
> The spec says this :-
>
> "As a contract, an assert represents a guarantee that the code
> must uphold. Any failure of this expression represents a logic
> error in the code that must be fixed in the source code. A
> program for which the assert contract is false is, by definition,
> invalid, and therefore has undefined behaviour."
>
> Now I worry about the words "undefined behavior" because in C++
> compiler writers seem to have decided that these words mean that
> it's ok for the compiler to generate code to do whatever it feels
> like even in unconnected code and even before the undefined
> behavior is invoked because some subsequent code has undefined
> behavior.
>
>  From my C++ experience this paragraph tells me that if I use
> "assert" to check my assumptions, and the assertion is false,
> then this could lead to my program failing in unpredictable ways
> unconnected with the actual assertion.
>
> I therefore feel like I ought to not use assert and should
> instead validate my assumptions with an if statement and a throw
> or exit or something.
>
> I feel like a failing assertion should not cause "undefined
> behavior" in the sense it is commonly used in C++ programming
> these days but should have exactly defined behavior that it will
> do nothing if the assert passes and throw the specified exception
> if it fails. Can I safely assume this despite the wording?
>
> I know this might seem like a small or pedantic point, but C++
> compilers can and do use invoking undefined behavior as an excuse
> to do all kinds of unexpected things in generated code these days
> and I want to write safe code :) I feel that if D is specified in
> the same way then assert is not safe for me to use in a real
> program.

If your assertions are failing, you're screwed anyway. If an assertion
fails, then by definition, your program is in an invalid state and who knows
what is going to happen. The whole point of assertions is to catch problems
during development so that you ensure that your code is correct. Not using
them is just making things worse for yourself.

The compiler _may_ use an assertion to inform its code generation by
assuming that the assertion is true (which certainly wouldn't cause you any
problems when not compiling with -release, since a failed assertions would
throw an AssertError and kill your program), and yes, in theory, if you
compile with -release, and an assertion would have failed, and the compiler
did something that assumed that the assertion passed, then maybe things
would be worse, but you're already screwed anyway, because your program is
in an invalid state, because the assertion wasn't true. In reality, I expect
that the compiler does very little at this point to optimize based on
assertions, but any time that it actually does will generally benefit you.

If you're concerned about compiling with -release and having an assertion
that would have failed not result in your program dying like it normally
would, then you can use assert(0), which will be translated to a HLT
instruction with -release. e.g.

if(!cond)
 assert(0);

instead of

assert(cond);

Regardless, you obviously shouldn't be using assertions for anything that
depends on user input. They're for detecting bugs in your program during
development. If you're truly using them for that, then you'll be better off
using them, and not using them is just begging for your program to have more
bugs that you didn't catch.

And the reality of the matter is that if you're looking to avoid undefined
behavior in general, you're screwed. Yes, D is much more likely to define
what should be happening than C/C++ is and thus has less undefined behavior
in general, but not ever allowing for undefined behavior would really harm
performance overall, because it really can help the compiler to optimize
code when it's not forced to do something less efficient just to make it so
that everything is fully defined, and pretty much any language you use is
going to have at least some undefined behavior.

Assertions are a great way to help ensure that you catch bugs in your
program, and if they can help the compiler optimize your code upon occasion,
then all the better (though honestly, I expect that they rarely have any
effect on the optimizer at this point given how little of the work on dmd is
geared towards better optimizing code; some work is done in that area to be
sure, but it's rarely the focus because of how much else needs to be done).

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list