www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - safety: null checks

reply Dibyendu Majumdar <mobile majumdar.org.uk> writes:
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.
Nov 22 2020
next sibling parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
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.
Nullpointer exceptions aren't a safety issue since the program crashes. For it to be a safety issue, it would need to have "bad consequences" e.g. writes to memory at locations the program isn't supposed to.
Nov 22 2020
parent reply Dibyendu Majumdar <mobile majumdar.org.uk> writes:
On Sunday, 22 November 2020 at 15:25:48 UTC, Q. Schroll wrote:
 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.
Nullpointer exceptions aren't a safety issue since the program crashes. For it to be a safety issue, it would need to have "bad consequences" e.g. writes to memory at locations the program isn't supposed to.
Right. A crash isn't a bad consequence, of course.
Nov 22 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 22 November 2020 at 22:16:11 UTC, Dibyendu Majumdar 
wrote:
 On Sunday, 22 November 2020 at 15:25:48 UTC, Q. Schroll wrote:
 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.
Nullpointer exceptions aren't a safety issue since the program crashes. For it to be a safety issue, it would need to have "bad consequences" e.g. writes to memory at locations the program isn't supposed to.
Right. A crash isn't a bad consequence, of course.
Memory safety is concerned specifically with avoiding undefined behavior. Crashing the program isn't undefined behavior, so it's allowed in safe code.
Nov 22 2020
parent reply Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
On Sunday, 22 November 2020 at 22:36:40 UTC, Paul Backus wrote:
 Memory safety is concerned specifically with avoiding undefined 
 behavior. Crashing the program isn't undefined behavior, so 
 it's allowed in  safe code.
I understand what you mean, but at high optimization levels dereferencing a null pointer can trigger undefined behaviour.
Nov 22 2020
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 22 November 2020 at 23:00:25 UTC, Ola Fosheim Grostad 
wrote:
 On Sunday, 22 November 2020 at 22:36:40 UTC, Paul Backus wrote:
 Memory safety is concerned specifically with avoiding 
 undefined behavior. Crashing the program isn't undefined 
 behavior, so it's allowed in  safe code.
I understand what you mean, but at high optimization levels dereferencing a null pointer can trigger undefined behaviour.
Then that's a bug in the compiler. A safe D program is allowed to dereference null, so a spec-conformant D compiler *must* ensure that dereferencing null has defined behavior.
Nov 22 2020
next sibling parent reply Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
On Sunday, 22 November 2020 at 23:28:26 UTC, Paul Backus wrote:
 Then that's a bug in the compiler. A  safe D program is allowed 
 to dereference null, so a spec-conformant D compiler *must* 
 ensure that dereferencing null has defined behavior.
Where does it say that? This won't work on embedded platforms. Not being allowed to reject buggy code would be bad...
Nov 22 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 22 November 2020 at 23:46:23 UTC, Ola Fosheim Grostad 
wrote:
 On Sunday, 22 November 2020 at 23:28:26 UTC, Paul Backus wrote:
 Then that's a bug in the compiler. A  safe D program is 
 allowed to dereference null, so a spec-conformant D compiler 
 *must* ensure that dereferencing null has defined behavior.
Where does it say that? This won't work on embedded platforms. Not being allowed to reject buggy code would be bad...
Ok, technically, a spec-confirming D implementation must either guarantee that dereferencing null has defined behavior, *or* forbid default initialization of pointers in safe code. The relevant part of the spec is the one on "safe values" [1]:
 A pointer is safe when:

    1. it can be dereferenced validly [i.e. with defined 
 behavior], and
    2. the value of the pointee is safe.
If null is a safe value, then dereferencing it must be defined behavior. If null is an unsafe value, then it must not be allowed to appear in safe code. Either way, a compiler that allows null in safe code but treats a null dereference as undefined behavior is buggy. [1] https://dlang.org/spec/function.html#safe-values
Nov 22 2020
parent reply Dibyendu Majumdar <mobile majumdar.org.uk> writes:
On Monday, 23 November 2020 at 00:17:12 UTC, Paul Backus wrote:

 The relevant part of the spec is the one on "safe values" [1]:

 A pointer is safe when:

    1. it can be dereferenced validly [i.e. with defined 
 behavior], and
    2. the value of the pointee is safe.
If null is a safe value, then dereferencing it must be defined behavior. If null is an unsafe value, then it must not be allowed to appear in safe code. Either way, a compiler that allows null in safe code but treats a null dereference as undefined behavior is buggy. [1] https://dlang.org/spec/function.html#safe-values
Hmm, null values are not the same as dereferncing null values. A null in itself is okay, but dereferencing null cannot be.
Nov 22 2020
parent reply Paul Backus <snarwin gmail.com> writes:
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."
Nov 22 2020
parent reply Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
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.
Nov 22 2020
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
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.
Nov 22 2020
parent reply Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
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.
Nov 22 2020
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 23 November 2020 at 01:29:12 UTC, Ola Fosheim Grostad 
wrote:
 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.
No. null is not a trap representation as a C standard would call it. It is a valid value for a pointer. Dereferencing it is an entirely other thing.
 Trivially invalid.
Nope.
 Please show me the relevant definitions of these terms and 
 explain how they contradict.
What do mean? A crash is by definition undefined behaviour.
Nope. In the case of D. The error generated by dereferencing a null pointer is a defined behaviour. As defined as is calling abort() in a C program. Catching the error and continuing processing that would be 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.
The issue with null pointer dereferencing has nothing to do with its definition but with its implementation as the defined behaviour of aborting the program is not guaranteed in all circumstances (null pointer + offset big enough to hit a real page).
Nov 23 2020
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 23 November 2020 at 12:28:39 UTC, Patrick Schluter 
wrote:
 No. null is not a trap representation as a C standard would 
 call it. It is a valid value for a pointer. Dereferencing it is 
 an entirely other thing.
A trap is an interrupt at the hardware level. It has nothing to do with C.
 Trivially invalid.
Nope.
Yes. "nothing" in not a valid value for "int". That is trivially invalid. Try to think of null as an empty set.
 Nope. In the case of D. The error generated by dereferencing a 
 null pointer is a defined behaviour. As defined as is calling 
 abort() in a C program.
You are speaking of DMD, not the spec?
 The issue with null pointer dereferencing has nothing to do 
 with its definition but with its implementation as the defined 
 behaviour of aborting the program is not guaranteed in all 
 circumstances (null pointer + offset big enough to hit a real 
 page).
My argument is based on the spec and what is required to get to something that is consistent/sound and portable. Also, as it has been pointed out, it does not work this way in shipping compilers so the spec should provide implemtation notes on what actually happens in shipping compilers.
Nov 23 2020
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Monday, 23 November 2020 at 12:39:05 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 23 November 2020 at 12:28:39 UTC, Patrick Schluter 
 wrote:
 No. null is not a trap representation as a C standard would 
 call it. It is a valid value for a pointer. Dereferencing it 
 is an entirely other thing.
A trap is an interrupt at the hardware level. It has nothing to do with C.
Read the C standard, they explain what a trap representation is. It has nothing to do with an interrupt. I refer to the C standard because they make the difference between allowed pointer values and unallowed values even if never dereferenced. Read the selected answer on this stackoverflow [1] page, he explains it better than me. [1]: https://stackoverflow.com/questions/6725809/trap-representation
Nov 23 2020
parent reply Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
On Monday, 23 November 2020 at 20:00:29 UTC, Patrick Schluter 
wrote:
 On Monday, 23 November 2020 at 12:39:05 UTC, Ola Fosheim 
 Grøstad wrote:
 A trap is an interrupt at the hardware level. It has nothing 
 to do with C.
Read the C standard, they explain what a trap representation is. It has nothing to do with an interrupt. I refer to the C standard because they make the difference between allowed pointer values and unallowed values even if never dereferenced.
When I intoduced the word "trap" in this discussion I used the traditional hardware terminology as used in Motorola 68K reference manuals. Has nothing to do with C whatsoever.
Nov 23 2020
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 24 November 2020 at 00:08:57 UTC, Ola Fosheim Grostad 
wrote:
 On Monday, 23 November 2020 at 20:00:29 UTC, Patrick Schluter 
 wrote:
 On Monday, 23 November 2020 at 12:39:05 UTC, Ola Fosheim 
 Grøstad wrote:
 A trap is an interrupt at the hardware level. It has nothing 
 to do with C.
Read the C standard, they explain what a trap representation is. It has nothing to do with an interrupt. I refer to the C standard because they make the difference between allowed pointer values and unallowed values even if never dereferenced.
When I intoduced the word "trap" in this discussion I used the traditional hardware terminology as used in Motorola 68K reference manuals. Has nothing to do with C whatsoever.
I introduced the expression "trap representation" from the C standard (and I specified explicitly the context I said "null is not a trap representation as a C standard would call it."). only be done either in bad faith, either from stupidity*. Choose your case. Bye, no further involvement from my part. * I know it's a false dichotomy, there's a third possibility but it is not positive for you either (you misunderstood and are too proud to admit it).
Nov 24 2020
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 24 November 2020 at 08:47:03 UTC, Patrick Schluter 
wrote:

 only be done either in bad faith, either from stupidity*.
I don't know what you are problem is here. Motorola terminology: trap Intel terminology: exception Both mean interrupt. I chose to use the term "trap" to avoid confusion.
Nov 24 2020
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 24 November 2020 at 08:47:03 UTC, Patrick Schluter 
wrote:
 I introduced the expression "trap representation" from the C 
 standard (and I specified explicitly the context I said "null 
 is not a trap representation as a C standard would call it.").

 only be done either in bad faith, either from stupidity*. 
 Choose your case.
Another note, please stop assuming what people are trying to cause harm to you. It is not productive. In case there is any doubt: I wrote "trap" with then intent of referring to a hardware exception. You seemed to read that in a more general sense and brought in the C standard, which is not relevant. So I can only assume that my intent was not conveyed as clearly as I wanted therefore I tried to make it clear. I apologize if you take offense by my attempt to make my intent clear. The C standard terminology is actually of no relevance when discussing the wording of the D spec: The pointee (object) is not valid for a null pointer, so it is indeed invalid (the pointee is).
Nov 24 2020
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
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.
Nov 22 2020
next sibling parent Paul Backus <snarwin gmail.com> writes:
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
Nov 22 2020
prev sibling parent reply Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
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.
Nov 22 2020
parent reply ag0aep6g <anonymous example.com> writes:
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.
Nov 22 2020
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 23 November 2020 at 02:21:20 UTC, ag0aep6g wrote:
 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.
Yes, the implementation dereferences null and traps it, but the in terms of the language it prevents dereferencing of null and terminates (as the dereferencing is supposed to be without other side effects than termination).
 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.
Yes, that does pose problems with objects of variable size. So then you either have to put a limit of how large objects nullable pointers are allowed to point to or add runtime checks. This is a good reason to add nonnullable pointers to the language. That would reduce the number of places where you need dynamic checks.
 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.
Indeed. Although specifications sometimes add implementation notes to clarify how things are supposed to work (so that an embedded compiler doesn't ignore runtime checks altogether). In the case of D, it would be interesting and useful to have implementation notes referring to what the different D compilers do.
Nov 23 2020
prev sibling parent Dibyendu Majumdar <mobile majumdar.org.uk> writes:
On Sunday, 22 November 2020 at 23:28:26 UTC, Paul Backus wrote:
 Then that's a bug in the compiler. A  safe D program is allowed 
 to dereference null, so a spec-conformant D compiler *must* 
 ensure that dereferencing null has defined behavior.
what spec? :)
Nov 22 2020
prev sibling parent reply Johan Engelen <j j.nl> writes:
On Sunday, 22 November 2020 at 23:00:25 UTC, Ola Fosheim Grostad 
wrote:
 On Sunday, 22 November 2020 at 22:36:40 UTC, Paul Backus wrote:
 Memory safety is concerned specifically with avoiding 
 undefined behavior. Crashing the program isn't undefined 
 behavior, so it's allowed in  safe code.
I understand what you mean, but at high optimization levels dereferencing a null pointer can trigger undefined behaviour.
I'll reiterate what I've been saying many times already: in LDC, null dereference in Undefined Behavior. What follows is that code should _actively_ check for null to be safe. Checking for null is not included by the compiler in safe code. - Note that accessing memory location 0x0 will probably crash your program on most systems, but definitely not all. For example with WebAssembly, 0 is a validly accessibly memory location. - "Dereferencing a null pointer" in D language context does _not_ mean accessing memory address 0 on system level. -- Calling a class method a.foo() when a==null is technically dereferencing `a`, even if the `foo` call is devirtualized, does not access any member variables, etc. -- Accessing struct member that is not at offset 0 will also lead to accesses to other locations than 0. -Johan
Nov 23 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 23 November 2020 at 12:01:08 UTC, Johan Engelen wrote:
 On Sunday, 22 November 2020 at 23:00:25 UTC, Ola Fosheim 
 Grostad wrote:
 On Sunday, 22 November 2020 at 22:36:40 UTC, Paul Backus wrote:
 Memory safety is concerned specifically with avoiding 
 undefined behavior. Crashing the program isn't undefined 
 behavior, so it's allowed in  safe code.
I understand what you mean, but at high optimization levels dereferencing a null pointer can trigger undefined behaviour.
I'll reiterate what I've been saying many times already: in LDC, null dereference in Undefined Behavior. What follows is that code should _actively_ check for null to be safe. Checking for null is not included by the compiler in safe code.
Then LDC allows memory corruption in safe code, which is a bug.
Nov 23 2020
parent reply Johan Engelen <j j.nl> writes:
On Monday, 23 November 2020 at 12:03:49 UTC, Paul Backus wrote:
 On Monday, 23 November 2020 at 12:01:08 UTC, Johan Engelen 
 wrote:
 I'll reiterate what I've been saying many times already: in 
 LDC, null dereference in Undefined Behavior. What follows is 
 that code should _actively_ check for null to be safe. 
 Checking for null is not included by the compiler in  safe 
 code.
Then LDC allows memory corruption in safe code,
Correct. And so do all other D compilers. Completely independent of optimization level.
 which is a bug.
Without explicit null pointer checking, this is effectively a "won't fix". -Johan
Nov 23 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 23 November 2020 at 16:50:44 UTC, Johan Engelen wrote:
 On Monday, 23 November 2020 at 12:03:49 UTC, Paul Backus wrote:
 Then LDC allows memory corruption in  safe code,
Correct. And so do all other D compilers. Completely independent of optimization level.
 which is a bug.
Without explicit null pointer checking, this is effectively a "won't fix".
Maybe it is for LDC. I suspect Walter puts a high enough priority on memory-safety that he would accept a fix for this issue into DMD.
Nov 23 2020
parent Dibyendu Majumdar <mobile majumdar.org.uk> writes:
On Monday, 23 November 2020 at 17:17:26 UTC, Paul Backus wrote:
 On Monday, 23 November 2020 at 16:50:44 UTC, Johan Engelen 
 wrote:
 On Monday, 23 November 2020 at 12:03:49 UTC, Paul Backus wrote:
 Then LDC allows memory corruption in  safe code,
Correct. And so do all other D compilers. Completely independent of optimization level.
 which is a bug.
Without explicit null pointer checking, this is effectively a "won't fix".
Maybe it is for LDC. I suspect Walter puts a high enough priority on memory-safety that he would accept a fix for this issue into DMD.
Hi, I think it is not fixable without introducing severe penalty in performance I suspect. Some languages are adding features to help the compiler / user specicify where nulls can be expected. Maybe D needs this too. My original issue was that it failed to check an obvious case. It seems that DMD does detect that case when -O is used. But that is perhaps not great. Other languages - even C or C+= these days, will immediately warn you about possible NULL de-reference when it is very obvious.
Nov 23 2020
prev sibling next sibling parent Max Haughton <maxhaton gmail.com> writes:
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.
Nov 22 2020
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
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.
Nov 22 2020