November 23, 2020
On Monday, 23 November 2020 at 00:26:26 UTC, Dibyendu Majumdar wrote:
>
> Hmm, null values are not the same as dereferncing null values.
> A null in itself is okay, but dereferencing null cannot be.

@safe code is allowed to dereference pointers, and there's no way for the compiler to know at compile time which pointers are null and which aren't. So, either @safe code must be forbidden from creating null pointers in the first place, or it must be allowed to dereference them.

Remember, @safe doesn't just mean "code that's memory safe", it means "code that the compiler can *prove* is memory safe."
November 23, 2020
On Monday, 23 November 2020 at 00:33:35 UTC, Paul Backus wrote:
> On Monday, 23 November 2020 at 00:26:26 UTC, Dibyendu Majumdar wrote:
>>
>> Hmm, null values are not the same as dereferncing null values.
>> A null in itself is okay, but dereferencing null cannot be.
>
> @safe code is allowed to dereference pointers, and there's no way for the compiler to know at compile time which pointers are null and which aren't. So, either @safe code must be forbidden from creating null pointers in the first place, or it must be allowed to dereference them.
>
> Remember, @safe doesn't just mean "code that's memory safe", it means "code that the compiler can *prove* is memory safe."

Well, the spec said that the value should be valid, which null by definition should not have, then the example comment mentioned a well defined crash which is a contradiction in terms.

So the spec is unsound.

What you would require from a high level language is that dereferencing null pointers is caught either at compile time or at runtime. But that is slow on some platforms. So this is just an example of the implementation being the spec, and actual document does not make sense in a general setting.

November 23, 2020
On Sunday, 22 November 2020 at 11:52:13 UTC, Dibyendu Majumdar wrote:
> import core.stdc.stdio : printf;
>
> extern (C++) abstract class A {
>     void sayHello();
> }
>
> extern (C++) class B : A {
>     override void sayHello() {
>         printf("hello\n");
>     }
> }
>
> extern (C) void main() {
>     //scope b = new B;
>     B b;
>     assert(b);
>     b.sayHello();
> }
>
>
> Above fails because b is null. But why doesn't the compiler say so? It seems like a very basic safety check.

Keep in mind that to find a null pointer, you must first invent the universe. This isn't a point about the halting problem, but rather than doing static analysis properly is complicated and dmd is already not particularly well structured.

You can use constant folding to find simple bugs like this, however, to do it in a clean manner requires a fair amount of thought to get right. Ideally you'd want to use some kind of complete design like abstract interpretation, but in reality you'll end up with @safe (minus the ownership aspects) where certain special cases are allowed.
November 23, 2020
On Monday, 23 November 2020 at 00:50:03 UTC, Ola Fosheim Grostad wrote:
> On Monday, 23 November 2020 at 00:33:35 UTC, Paul Backus wrote:
>>
>> @safe code is allowed to dereference pointers, and there's no way for the compiler to know at compile time which pointers are null and which aren't. So, either @safe code must be forbidden from creating null pointers in the first place, or it must be allowed to dereference them.
>>
>> Remember, @safe doesn't just mean "code that's memory safe", it means "code that the compiler can *prove* is memory safe."
>
> Well, the spec said that the value should be valid, which null by definition should not have,

Please show me the definition of null that requires it to be invalid.

> then the example comment mentioned a well defined crash which is a contradiction in terms.
>
> So the spec is unsound.

Please show me the relevant definitions of these terms and explain how they contradict.

> What you would require from a high level language is that dereferencing null pointers is caught either at compile time or at runtime. But that is slow on some platforms. So this is just an example of the implementation being the spec, and actual document does not make sense in a general setting.

The implementation allows undefined behavior in @safe code. That means the implementation is incorrect, period. Neither of the possible interpretations of the spec allow this.
November 23, 2020
On Monday, 23 November 2020 at 00:50:03 UTC, Ola Fosheim Grostad wrote:
> Well, the spec said that the value should be valid, which null by definition should not have, then the example comment mentioned a well defined crash which is a contradiction in terms.
>
> So the spec is unsound.

I wrote that part of the spec. My intent was to define null as a safe value. For other pointer-like types I wrote: "A [thing] is safe when it is `null` or [whatever]". Please feel free to add that phrase for pointers, too, or adjust the text in any other way that makes it more clear that null is a safe value.

> What you would require from a high level language is that dereferencing null pointers is caught either at compile time or at runtime. But that is slow on some platforms. So this is just an example of the implementation being the spec, and actual document does not make sense in a general setting.

The reference implementation treats null as a safe value. Yes, that can imply additional checks at run time. That's what Walter chose, for better or worse.
November 23, 2020
On Monday, 23 November 2020 at 01:04:38 UTC, Paul Backus wrote:
> Please show me the definition of null that requires it to be invalid.

null points to nothing, that is not a valid value for the referenced type.

Trivially invalid.

> Please show me the relevant definitions of these terms and explain how they contradict.

What do mean? A crash is by definition undefined behaviour.

The spec does not provide adequate definitions and requirements, which is what makes it unsound.

> The implementation allows undefined behavior in @safe code. That means the implementation is incorrect, period. Neither of the possible interpretations of the spec allow this.

The spec isn't well defined or consistent just because people claim things in the forum.


November 23, 2020
On Monday, 23 November 2020 at 01:26:15 UTC, ag0aep6g wrote:
> Please feel free to add that phrase for pointers, too, or adjust the text in any other way that makes it more clear that null is a safe value.

https://github.com/dlang/dlang.org/pull/2884
November 23, 2020
On Monday, 23 November 2020 at 01:26:15 UTC, ag0aep6g wrote:
> The reference implementation treats null as a safe value. Yes, that can imply additional checks at run time. That's what Walter chose, for better or worse.

It traps null dereferencing unless the object is very large.

I think it should state clearly whether that is portable or specific for Posix-like systems. Does it require explicit null check conditionals on platforms that do not provide traps?

That is what has to be clarified.
November 23, 2020
On Monday, 23 November 2020 at 01:36:38 UTC, Ola Fosheim Grostad wrote:
> On Monday, 23 November 2020 at 01:26:15 UTC, ag0aep6g wrote:
>> The reference implementation treats null as a safe value. Yes, that can imply additional checks at run time. That's what Walter chose, for better or worse.
>
> It traps null dereferencing unless the object is very large.

What I meant is that DMD allows dereferencing null in @safe code. Since @safe code must not corrupt memory, it must then take the necessary steps to make that safe.

I'm pretty sure that DMD doesn't actually take the necessary steps (as you say, it ignores large objects). And I'm not sure if Walter has fully considered the implications, but he has made it clear that null is supposed to be a safe value. And that can be made to work fairly easily, at the cost of run-time checks. Maybe treating null as unsafe could also work, but that would need a lot more design work.

> I think it should state clearly whether that is portable or specific for Posix-like systems. Does it require explicit null check conditionals on platforms that do not provide traps?
>
> That is what has to be clarified.

I think that's an implementation detail. An implementation must ensure that null is safe (at least in @safe code). We don't really care how it does that, but adding checks before every dereference is the obvious solution.
November 23, 2020
On Sunday, 22 November 2020 at 11:52:13 UTC, Dibyendu Majumdar wrote:
> Above fails because b is null. But why doesn't the compiler say so? It seems like a very basic safety check.

Try this just for laughs:

remove the assert then add the -O switch.

$ dmd -betterC lole -O
lole.d(16): Error: null dereference in function main


(the assert actually disables this because the optimizer sees that and then figures the function must not be null.)

It just amuses me that dmd's *optimizer* actually catches this, but the debug build doesn't. Walter explained it is because the optimizer is analyzing the data flow anyway so it was a free check at that point, whereas on a normal or debug build it is a bunch of extra work for the implementation. Or something like that, don't trust my memory completely.

But yeah it makes me lol.