On 3/1/18 5:27 PM, ag0aep6g wrote:
You're looking at the behavior of the compiled executable. Then it makes
sense to say that a program compiled with the checks has defined
behavior (throwing Errors) and a program without the checks does
something undefined (because the compiler manual doesn't say that
anything in particular is supposed to happen).
No, I'm looking at the source code.
At the very basic level, you have this:
assert(foo == 0);
Or whatever other condition you have. What this does is gives the
compiler leeway to ASSUME foo is 0 at this point. It can make any number
of optimizations assuming this. If foo is NOT equal to 0 at this point,
then it is a program error, and the assumptions may cause bad things to
happen.
When you compile in normal mode, this assert causes an Error to be
thrown, before your code can do any damage.
When you compile without asserts, this causes undefined behavior.
The various switches and modes can say whether asserts or other checks
are present or not, and if they are not, the compiler is going to
execute your UB code with those wrong assumptions. But ONLY if the
assert would have been false.
I extend this same treatment and logic to all checks: contracts, bounds
checks, overlapping slice assign checks, etc. To me, they aren't any
different than asserts. They aren't any different if they are in @safe
code or @system code.
That's not how I understand/use "undefined behavior". To me, it's the D
source code that can have "undefined behavior". When it does, the
program (as given in source code) is invalid and the compiler can do
whatever it wants with it. It may:
1) reject the program statically, or it may
2) generate code that throws an Error at run time, or it may
3) generate code that does something arbitrary.
With that meaning of UB, out-of-bounds accesses and overlapping copies
have undefined behavior in @system code, but they have defined behavior
in @safe code.
By default, both @system and @safe code have bounds checks. So by
default, it is defined behavior (an Error is thrown) regardless of the
safety.
If you turn the checks off (through any means) then it becomes UB.
In this interpetation, -noboundscheck switches DMD to a different
dialect of D. In that dialect, out-of-bounds accesses (and overlapping
copies, apparently) always have UB, in both @system and @safe code. That
defeats the purpose of @safe. Which is why I don't really care for that
dialect.
I agree, I think we should remove the option to disable bounds checks on
@safe code, in any way. It's too dangerous. If you want performance that
comes without bounds checks, use a trusted escape, or write system code.
-Steve