On Thursday, 27 July 2017 at 15:03:02 UTC, Steven Schveighoffer
wrote:
Inside the thread for adding @safe/@trusted attributes to OS
functions, it has come to light that @safe has conflicting
rules.
For the definition of safe, it says:
"Safe functions are functions that are statically checked to
exhibit no possibility of undefined behavior."
In the definition of @trusted, it says:
"Trusted functions are guaranteed by the programmer to not
exhibit any undefined behavior if called by a safe function."
Yet, safe functions allow dereferencing of null pointers.
Example:
void foo() @safe
{
int *x;
*x = 5;
}
There are various places on the forum where Walter argues that
null pointer dereferencing should cause a segmentation fault
(or crash) and is checked by the hardware/OS. Therefore,
checking for null pointers before any dereferencing would be a
waste of cycles.
However, there do exist places where dereferencing null may NOT
cause a segmentation fault. For example, see this post by
Moritz Maxeiner:
https://forum.dlang.org/post/[email protected]
In such cases, the compiled program can have no knowledge that
the zero page is mapped somehow. There is no way to prevent it,
or guarantee it during compilation.
It's also worth noting that C/C++ identifies null dereferencing
as undefined behavior. So if we are being completely pedantic,
we could say that no C/C++ code could be marked safe if there
is a possibility that a null pointer would be dereferenced.
The way I see it, we have 2 options. First, we can disallow
null pointer dereferencing in @safe code. This would be hugely
disruptive. We may not have to instrument all @safe code with
null checks, we could do it with flow analysis, and assuming
that all pointers passed into a @safe function are not null.
But it would likely disallow a lot of existing @safe code.
The other option is to explicitly state what happens in such
cases. I would opt for this second option, as the likelihood of
these situations is very low.
If we were to update the spec to take this into account, how
would it look?
A possibility:
"@safe D does not support platforms or processes where
dereferencing a null pointer does not crash the program. In
such situations, dereferencing null is not defined, and @safe
code will not prevent this from happening."
In terms of not marking C/C++ code safe, I am not convinced we
need to go that far, but it's not as horrible a prospect as
having to unmark D @safe code that might dereference null.
Thoughts?
-Steve
Why can't we just make the compiler insert null checks in @safe
code? We can afford bounds checking even in @system -O -release.
C++ can afford null check upon executing an std::function. The
pointer would most likely be in a register anyway, and the
conditional branch would almost always not be taken, so the cost
of that check would be barely measurable. Moreover, the compiler
can elide the check e.g. if the access via pointer is made in a
loop in which the pointer doesn't change. And if you prove that
this tiny little check ruins performance of your code, there's
@trusted to help you.