November 18, 2017
On Saturday, 18 November 2017 at 03:33:00 UTC, codephantom wrote:
> If your code dereferences a null pointer, and the program segfaults, and that program is supplying me with the oxygen i need to survive...then its probably not safe ;-)

If you have a life-essential system that can't survive a single part randomly failing, including a process terminating abnormally, you're an incompetent engineer.
November 18, 2017
On Friday, 17 November 2017 at 15:27:06 UTC, Jesse Phillips wrote:
> It is interesting that you mention this. Our product manager was talking to our senior developer about this very thing. He explained that it was a method of development that an employee at his previous company came up with at that the approach was very effective once implemented.
>

Just give it a nice 'product' name, like "Conscientious Defensive Programming".

Now it's a lot easier to get people on board, even senior management ;-)


November 17, 2017
On 11/17/2017 6:05 AM, Timon Gehr wrote:
> There are type systems that do that, which is what is being proposed for C#. It's pretty straightforward: If I have a variable of class reference type C, it actually contains a reference to a class instance of type C.

One of the difficulties with this is you'll still need an "empty" instance of C for the non-null reference to point to. Any attempts to use a method on the empty instance should throw.

Which is pretty much what a null reference does.

(It's also more or less what floating point NaNs do, where every operation on a NaN produces a NaN as a result.)
November 17, 2017
On 11/16/2017 5:47 PM, Michael V. Franklin wrote:
> the lack of any warning or error for this trivial case surprised me.

Consider the following code:

  void test() {
    int* p;
    *p = 3;
  }

Compiling it with -O gives:

  Error: null dereference in function _D5test54testFNaZv

The -O is necessary because the optimizer uses data flow analysis, which makes the error easy to pick up.

Note that if the code were written:

  void test(int i) {
    int* p;
    if (i) p = &i;
    *p = 3;
  }

no error is diagnosed. Data flow analysis determines all paths, and some of those paths may (legitimately) never happen, and so giving an error would be spurious.
November 18, 2017
On Saturday, 18 November 2017 at 03:39:50 UTC, Adam D. Ruppe wrote:
>
> If you have a life-essential system that can't survive a single part randomly failing, including a process terminating abnormally, you're an incompetent engineer.

First semester, programming course.

Write a life-essential system in C, and simulate it.

If patient dies, you fail.

November 18, 2017
On Saturday, 18 November 2017 at 04:56:19 UTC, codephantom wrote:
> First semester, programming course.
>
> Write a life-essential system in C, and simulate it.
>
> If patient dies, you fail.


Second semester. Find vulnerability in another students semester 1 project.

If you succeed, they fail the whole year, you pass second semester.

I bet we'd see a lot of conscientuous defensive programming in semester 1 ;-)
November 18, 2017
On 18.11.2017 05:05, Walter Bright wrote:
> On 11/17/2017 6:05 AM, Timon Gehr wrote:
>> There are type systems that do that, which is what is being proposed for C#. It's pretty straightforward: If I have a variable of class reference type C, it actually contains a reference to a class instance of type C.
> 
> One of the difficulties with this is you'll still need an "empty" instance of C for the non-null reference to point to.

Why would you need an empty instance? Just use a Nullable!C instead of a C if a special 'null' state is actually required.

> Any attempts to use a method on the empty instance should throw. 

The idea is that the type system makes potential such attempts explicit while verifying that they don't occur in most of the cases. Then you can grep for potential null dereferences.
November 18, 2017
On 17.11.2017 15:53, Jonathan M Davis wrote:
> On Friday, November 17, 2017 15:05:48 Timon Gehr via Digitalmars-d wrote:
>> On 17.11.2017 12:22, Jonathan M Davis wrote:
>>> On Friday, November 17, 2017 09:44:01 rumbu via Digitalmars-d wrote:
>>>> I know your aversion towards C#, but this not about C#, it's
>>>> about safety. And safety is one of the D taglines.
>>> Completely aside from whether having the compile-time checks would be
>>> good or not, I would point out that this isn't actually a memory safety
>>> issue.
>> Memory safety is not the only kind of safety. Also, memory safety is
>> usually formalized as (type) preservation which basically says that
>> every memory location actually contains a value of the correct type.
>> Hence, as soon as you have non-nullable pointers in the type system,
>> this_becomes_  a memory safety issue.
> This is definitely not how it is viewed in D. Walter has repeatedly stated
> that dereferencing a null pointer is considered @safe, because doing so will
> not corrupt memory or access memory that it should not access - and that's
> all that @safe cares about.

The current discussion is about how safety *should* be viewed in D in the future, as in, potentially /changing/ how it is viewed. This means rehashing the status quo without giving justification for it is not useful. Why *should* @safe only mean "does not corrupt memory" or "accesses memory that it should not access"? Why can't it also mean "does not attempt to dereference null pointers"? Note that it is up to the language to _define_ what @safe does and does not mean. If the language evolves, that meaning may evolve too.
November 18, 2017
On 11/18/2017 6:16 AM, Timon Gehr wrote:
> On 18.11.2017 05:05, Walter Bright wrote:
>> On 11/17/2017 6:05 AM, Timon Gehr wrote:
>>> There are type systems that do that, which is what is being proposed for C#. It's pretty straightforward: If I have a variable of class reference type C, it actually contains a reference to a class instance of type C.
>>
>> One of the difficulties with this is you'll still need an "empty" instance of C for the non-null reference to point to.
> 
> Why would you need an empty instance?

Consider the ClassDeclaration in the DMD source. Each ClassDeclaration has a pointer to its base class, `baseClass`. Except for `Object`, which doesn't have a base class. This is represented to assigning `null` to `baseClass`.

So I can run up the base class list by:

    for (b = c; b; b = b.baseClass) { ... }

If it cannot be null, I just have to invent something else that does the same thing:

    for (b = c; b != nullInstanceOfClass; b = b.baseClass) { ... }

and nothing really has changed.

> Just use a Nullable!C instead of a C if a special 'null' state is actually required.

What should the default initializer for a type do?


>> Any attempts to use a method on the empty instance should throw. 
> 
> The idea is that the type system makes potential such attempts explicit while verifying that they don't occur in most of the cases. Then you can grep for potential null dereferences.

There are cases where the actual path taken guarantees initialization, but the graph of all paths does have uninitialized edges. Figuring out which are paths never taken is the halting problem. I found this out when testing my DFA (data flow analysis) algorithms.

  void test(int i) {
    int* p = null;
    if (i) p = &i;
    ...
    if (i) *p = 3;
    ...
  }

Note that the code is correct, but DFA says the *p could be a null dereference. (Replace (i) with any complex condition that there's no way the DFA can prove always produces the same result the second time.)
November 18, 2017
On Saturday, November 18, 2017 15:24:49 Timon Gehr via Digitalmars-d wrote:
> On 17.11.2017 15:53, Jonathan M Davis wrote:
> > On Friday, November 17, 2017 15:05:48 Timon Gehr via Digitalmars-d
wrote:
> >> On 17.11.2017 12:22, Jonathan M Davis wrote:
> >>> On Friday, November 17, 2017 09:44:01 rumbu via Digitalmars-d wrote:
> >>>> I know your aversion towards C#, but this not about C#, it's about safety. And safety is one of the D taglines.
> >>>
> >>> Completely aside from whether having the compile-time checks would be
> >>> good or not, I would point out that this isn't actually a memory
> >>> safety
> >>> issue.
> >>
> >> Memory safety is not the only kind of safety. Also, memory safety is usually formalized as (type) preservation which basically says that every memory location actually contains a value of the correct type. Hence, as soon as you have non-nullable pointers in the type system, this_becomes_  a memory safety issue.
> >
> > This is definitely not how it is viewed in D. Walter has repeatedly stated that dereferencing a null pointer is considered @safe, because doing so will not corrupt memory or access memory that it should not access - and that's all that @safe cares about.
>
> The current discussion is about how safety *should* be viewed in D in the future, as in, potentially /changing/ how it is viewed. This means rehashing the status quo without giving justification for it is not useful. Why *should* @safe only mean "does not corrupt memory" or "accesses memory that it should not access"? Why can't it also mean "does not attempt to dereference null pointers"? Note that it is up to the language to _define_ what @safe does and does not mean. If the language evolves, that meaning may evolve too.

@safe as it stands provides a way to segregate code that potentially introduces memory corruption and invalid memory accesses. Trying to add anything related to null pointer dereferencing would just increase the amount of code that would have to be @system, making it harder to deal with problems actually related to memory corruption. And really, to avoid the possibility of dereferencing null would require introducing non-nullable pointers and references, because you're never going to be able to guarantee it for nullable pointers or references, and honestly, I think that it would destroy @safe to treat dereferencing nullable pointers or references as @system. Too much code would be @system, making it far more difficult to segregate code that dealt with actual, memory safety issues.

Perhaps there would be some value in having non-nullable pointers or references, but they're an issue orthogonal to memory safety. And honestly, I'm not even vaguely convinced that null pointers or references are much of a real problem. Personally, pretty much the only time I run into problems with them is when I forget to initialize a class reference. It's incredibly rare that I end up with a program that ends up dereferencing null. And when it does, you get a segfault and potentially a core dump, and the problem is usually easy to fix.

Really, I don't think that dealing with potentially dereferencing null is all that different from dealing with potentially dividing by zero. It sucks when it happens, because it kills your program, but it's really not all that hard to avoid. And at least when it does happen, it's obvious rather than introducing subtle and hard to track down problems like you frequently get with code that isn't memory safe.

- Jonathan M Davis