November 16, 2009
Denis Koroskin wrote:
> On Mon, 16 Nov 2009 19:27:41 +0300, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> 
>> bearophile wrote:
>>> Walter Bright:
>>>
>>>> A person using alloca is expecting stack allocation, and that it goes away after the function exits. Switching arbitrarily to the gc will not be detected and may hide a programming error (asking for a gigantic piece of memory is not anticipated for alloca, and could be caused by an overflow or logic error in calculating its size).
>>>  There's another solution, that I'd like to see more often used in Phobos: you can add another function to Phobos, let's call it salloca (safe alloca) that does what Denis Koroskin asks for (it's a very simple function).
>>
>> Can't be written. Try it.
>>
>> Andrei
> 
> It's tricky. It can't be written *without a compiler support*, because it is considered special for a compiler (it always inlines the call to it). It could be written otherwise.
> 
> I was thinking about proposing either an inline keyword in a language (one that would enforce function inlining, rather than suggesting it to compiler), or allways inline all the functions that make use of alloca. Without either of them, it is impossible to create wrappers around alloca (for example, one that create arrays on stack type-safely and without casts):
> 
> T[] array_alloca(T)(size_t size) { ... }
> 
> or one that would return GC-allocated memory when stack allocation fails:
> 
> void* salloca(size_t size) {
>     void* ptr = alloca(size);
>     if (ptr is null) return (new void[size]).ptr;
> 
>     return ptr;
> }

The problem of salloca is that alloca's memory gets released when salloca returns.

Andrei
November 16, 2009
dsimcha wrote:
> Yes, but it stops the program in such a way that it's very hard to figure out
> why/where it died.

I don't want to get into another loooong thread about should pointers be nullable or not, I just wished to point out that it was not a *safety* issue.
November 16, 2009
Walter Bright:

> I don't want to get into another loooong thread about should pointers be nullable or not,

It was a good thread with good ideas.


>I just wished to point out that it was not a *safety* issue.<

A safe system is not a program that switches itself off as soon as there's a small problem.

One Ariane missile has self-destroyed (and destroyed an extremely important scientific satellite it was carrying whose mission I miss still) because of this silly behaviour united with the inflexibility of the Ada language.

A reliable system is a systems that keeps working correctly despite all. If this is not possible, in real life you usually want a "good enough" behaviour. For example, for your TAC medical machine, in Africa if the machine switches itself off at the minimal problem they force the machine to start again, because they don't have money for a 100% perfect fix. So for them it's better a machine that shows a slow and graceful degradation. That's a reliable system, something that looks more like your liver, that doesn't totally switch off as soon it has a small problem (killing you quickly).

A program that stops working in a random moment because of a null is not safe. (And even if you accept this, in safer languages like C#/Java there are null exceptions that show a stack trace. The type system is smart enough to remove most of those tests to improve performance). A safer program is a program that avoids null pointer exception because the type system has formally verified the program has no nulls.

Bye,
bearophile
November 16, 2009
== Quote from bearophile (bearophileHUGS@lycos.com)'s article
> Walter Bright:
> > I don't want to get into another loooong thread about should pointers be nullable or not,
> It was a good thread with good ideas.
> >I just wished to point out that it was not a *safety* issue.<
> A safe system is not a program that switches itself off as soon as there's a
small problem.
> One Ariane missile has self-destroyed (and destroyed an extremely important
scientific satellite it was carrying whose mission I miss still) because of this silly behaviour united with the inflexibility of the Ada language.
> A reliable system is a systems that keeps working correctly despite all. If this
is not possible, in real life you usually want a "good enough" behaviour. For example, for your TAC medical machine, in Africa if the machine switches itself off at the minimal problem they force the machine to start again, because they don't have money for a 100% perfect fix. So for them it's better a machine that shows a slow and graceful degradation. That's a reliable system, something that looks more like your liver, that doesn't totally switch off as soon it has a small problem (killing you quickly).
> A program that stops working in a random moment because of a null is not safe.
(And even if you accept this, in safer languages like C#/Java there are null exceptions that show a stack trace. The type system is smart enough to remove most of those tests to improve performance). A safer program is a program that avoids null pointer exception because the type system has formally verified the program has no nulls.
> Bye,
> bearophile

In a way you're right.  However, there is no universal answer for what to do about
a null pointer except die **with a good error message explaining what went
wrong**.  This is the part that's missing.  Right now you get an access violation.
 I'd like an assert failure with a line number and a "Null pointer dereference"
error message when I'm not in release mode.
November 16, 2009
bearophile wrote:
> Walter Bright:
> 
>> I don't want to get into another loooong thread about should
>> pointers be nullable or not,
> 
> It was a good thread with good ideas.
> 
> 
>> I just wished to point out that it was not a *safety* issue.<
> 
> A safe system is not a program that switches itself off as soon as
> there's a small problem.
> 
> One Ariane missile has self-destroyed (and destroyed an extremely
> important scientific satellite it was carrying whose mission I miss
> still) because of this silly behaviour united with the inflexibility
> of the Ada language.
> 
> A reliable system is a systems that keeps working correctly despite
> all. If this is not possible, in real life you usually want a "good
> enough" behaviour. For example, for your TAC medical machine, in
> Africa if the machine switches itself off at the minimal problem they
> force the machine to start again, because they don't have money for a
> 100% perfect fix. So for them it's better a machine that shows a slow
> and graceful degradation. That's a reliable system, something that
> looks more like your liver, that doesn't totally switch off as soon
> it has a small problem (killing you quickly).
> 
> A program that stops working in a random moment because of a null is
> not safe. (And even if you accept this, in safer languages like
> C#/Java there are null exceptions that show a stack trace. The type
> system is smart enough to remove most of those tests to improve
> performance). A safer program is a program that avoids null pointer
> exception because the type system has formally verified the program
> has no nulls.
> 
> Bye, bearophile

I think it all has to do with definitions. If you define safety as a yes/no property, then there can be no discussion about "safer".

The classic safety definition involves progress and preservation. If those are satisfied for all programs, the language is safe. All languages in actual use cannot satisfy progress for all programs, which makes the definition too restrictive. So people use more relaxed definitions, e.g. allow for stuck states (e.g. use of a null pointer is a stuck state) or work in terms of trapped vs. untrapped errors.

D's definition of safety is "no undefined behavior" which is as far as I can understand a tight superset of "no untrapped errors". If we go by that definition we can't talk about safer or less safe. You either have UB or don't.

That being said, I like non-null references. The problem is that as soon as someone tries to enumerate safety among the desirable behaviors of non-null references, Walter's regard for the argument completely shuts down, taking down with it all good arguments too.


Andrei
November 16, 2009
bearophile wrote:
> Walter Bright:
>> I just wished to point out that it was not a *safety* issue.<
> A safe system is not a program that switches itself off as soon as
> there's a small problem.

Computers cannot know whether a problem is "small" or not.

> One Ariane missile has self-destroyed (and destroyed an extremely
> important scientific satellite it was carrying whose mission I miss
> still) because of this silly behaviour united with the inflexibility
> of the Ada language.
> 
> A reliable system is a systems that keeps working correctly despite
> all. If this is not possible, in real life you usually want a "good
> enough" behaviour. For example, for your TAC medical machine, in
> Africa if the machine switches itself off at the minimal problem they
> force the machine to start again, because they don't have money for a
> 100% perfect fix. So for them it's better a machine that shows a slow
> and graceful degradation. That's a reliable system, something that
> looks more like your liver, that doesn't totally switch off as soon
> it has a small problem (killing you quickly).

This is how you make reliable systems:

http://dobbscodetalk.com/index.php?option=com_myblog&show=Safe-Systems-from-Unreliable-Parts.html&Itemid=29

http://dobbscodetalk.com/index.php?option=com_myblog&show=Designing-Safe-Software-Systems-Part-2.html&Itemid=29

Pretending a program hasn't failed when it has, and just "soldiering on", is completely unacceptable behavior in a system that must be reliable.

The Ariane 5 had a backup system which was engaged, but the backup system had the same software in it, so failed in the same way. That is not how you make reliable systems.


> A program that stops working in a random moment because of a null is
> not safe. (And even if you accept this, in safer languages like
> C#/Java there are null exceptions that show a stack trace. The type
> system is smart enough to remove most of those tests to improve
> performance). A safer program is a program that avoids null pointer
> exception because the type system has formally verified the program
> has no nulls.

You're using two different definitions of the word "safe". Program safety is about not corrupting memory. System safety (i.e. reliability) is a completely different thing.

If you've got a system that relies on the software continuing to function after an unexpected null seg fault, you have a VERY BADLY DESIGNED and COMPLETELY UNSAFE system. I really cannot emphasize this enough.

P.S. I worked for Boeing for years on flight critical systems. Normally I eschew credentialism, but I feel very strongly about this issue and wish to point out that my knowledge on this is based on decades of real world experience by aviation companies who take this issue extremely seriously.

November 16, 2009
dsimcha wrote:
> In a way you're right.  However, there is no universal answer for what to do about
> a null pointer except die **with a good error message explaining what went
> wrong**.  This is the part that's missing.  Right now you get an access violation.
>  I'd like an assert failure with a line number and a "Null pointer dereference"
> error message when I'm not in release mode.

You do get just that if you run the program under a debugger.

There was a patch for Phobos a while back which would use the debug data to print a stack trace on such an exception without needing a debugger. It has languished because nobody has spent the time to verify that it is correctly done and that it won't negatively impact anything else. I can forward it to you if you like and want to take a look at it.
November 16, 2009
Walter Bright wrote:
> dsimcha wrote:
>> In a way you're right.  However, there is no universal answer for what to do about
>> a null pointer except die **with a good error message explaining what went
>> wrong**.  This is the part that's missing.  Right now you get an access violation.
>>  I'd like an assert failure with a line number and a "Null pointer dereference"
>> error message when I'm not in release mode.
> 
> You do get just that if you run the program under a debugger.
> 
> There was a patch for Phobos a while back which would use the debug data to print a stack trace on such an exception without needing a debugger. It has languished because nobody has spent the time to verify that it is correctly done and that it won't negatively impact anything else. I can forward it to you if you like and want to take a look at it.

It's in Tango and it works. Both on Linux and Windows.
(Needs the Tango svn version.)
November 16, 2009
On Mon, Nov 16, 2009 at 03:19:06PM -0500, bearophile wrote:
> One Ariane missile has self-destroyed (and destroyed an extremely important scientific satellite it was carrying whose mission I miss still) because of this silly behaviour united with the inflexibility of the Ada language.

Would you have preferred it to just randomly do its own thing and potentially
end up landing on people? Blowing it up over the ocean or the launch site
is something they would be prepared for anyway, so it is relatively safe to
people, which is what ultimately matters. Even expensive, important pieces
of equipment can always be replaced.

> A program that stops working in a random moment because of a null is not safe.

What would you have it do? Carry on in the error state, doing Lord knows what? That's clearly unsafe.

Terminating it is a completely predictable situation - one you can design the safe system as a whole around.

The rocket scientists know their rocket might blow up at launch, so they build the launch pad out far enough from people and schedule lift off on a day with favourable weather, so if it does explode, the odds of someone getting hurt are low.

Hospitals know their medical machines might screw up, so they keep a nurse on duty at all times who can handle the situation - restart the failed machine, or bring in a replacement before it kills someone.


Similarly, if your program simply must not fail, null pointer problems don't preclude this. You can predict the eventuality of termination, and set up an external process to restart the dead program:

	while [ true ] ; do ./buggy-program ; done

It might not be convenient all the time, but it is safe. Certainly safer than the alternative of carrying on in an unknown state.

> A safer program is a program that avoids null pointer exception because the type system has formally verified the program has no nulls.

I wouldn't say safer, though I will concede that it is easier to debug.


-- 
Adam D. Ruppe
http://arsdnet.net
November 16, 2009
Andrei Alexandrescu wrote:
> Denis Koroskin wrote:
>> On Mon, 16 Nov 2009 19:27:41 +0300, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>>
>>> bearophile wrote:
>>>> Walter Bright:
>>>>
>>>>> A person using alloca is expecting stack allocation, and that it goes away after the function exits. Switching arbitrarily to the gc will not be detected and may hide a programming error (asking for a gigantic piece of memory is not anticipated for alloca, and could be caused by an overflow or logic error in calculating its size).
>>>>  There's another solution, that I'd like to see more often used in Phobos: you can add another function to Phobos, let's call it salloca (safe alloca) that does what Denis Koroskin asks for (it's a very simple function).
>>>
>>> Can't be written. Try it.
>>>
>>> Andrei
>>
>> It's tricky. It can't be written *without a compiler support*, because it is considered special for a compiler (it always inlines the call to it). It could be written otherwise.
>>
>> I was thinking about proposing either an inline keyword in a language (one that would enforce function inlining, rather than suggesting it to compiler), or allways inline all the functions that make use of alloca. Without either of them, it is impossible to create wrappers around alloca (for example, one that create arrays on stack type-safely and without casts):
>>
>> T[] array_alloca(T)(size_t size) { ... }
>>
>> or one that would return GC-allocated memory when stack allocation fails:
>>
>> void* salloca(size_t size) {
>>     void* ptr = alloca(size);
>>     if (ptr is null) return (new void[size]).ptr;
>>
>>     return ptr;
>> }
> 
> The problem of salloca is that alloca's memory gets released when salloca returns.
> 
> Andrei

template salloca(alias ptr, alias size) { // horrible name, btw
  ptr = alloca(size);
  if (ptr is null) ptr = (new void[size]).ptr;
}

// use:
void foo() {
  int size = 50;
  void* ptr;
  mixin salloca!(ptr, size);
  //...
}

wouldn't that work?