dereferencing null

Steven Schveighoffer schveiguy at yahoo.com
Wed Mar 7 04:57:41 PST 2012


On Mon, 05 Mar 2012 23:58:48 -0500, Chad J  
<chadjoan at __spam.is.bad__gmail.com> wrote:

> On 03/05/2012 11:27 PM, Jonathan M Davis wrote:
>> On Tuesday, March 06, 2012 05:11:30 Martin Nowak wrote:
>>> There are two independent discussions being conflated here. One about
>>> getting more
>>> information out of crashes even in release mode and the other about
>>> adding runtime checks to prevent crashing merely in debug builds.
>>
>> A segfault should _always_ terminate a program - as should  
>> dereferencing a
>> null pointer. Those are fatal errors. If we had extra checks, they  
>> would have
>> to result in NullPointerErrors, not NullPointerExceptions. It's horribly
>> broken to try and recover from dereferencing a null pointer. So, the  
>> question
>> then becomes whether adding the checks and getting an Error thrown is  
>> worth
>> doing as opposed to simply detecting it and printing out a stack trace.  
>> And
>> throwing an Error is arguably _worse_, because it means that you can't  
>> get a
>> useful core dump.
>>
>> Really, I think that checking for null when dereferencing is out of the
>> question. What we need is to detect it and print out a stacktrace. That  
>> will
>> maximize the debug information without costing performance.
>>
>> - Jonathan M Davis
>
> Why is it fatal?

A segmentation fault indicates that a program tried to access memory that  
is not available.  Since the 0 page is never allocated, any null pointer  
dereferencing results in a seg fault.

However, there are several causes of seg faults:

1. You forgot to initialize a variable.
2. Your memory has been corrupted, and some corrupted pointer now points  
into no-mem land.
3. You are accessing memory that has been deallocated.

Only 1 is benign.  2 and 3 are fatal.  Since you cannot know which of  
these three happened, the only valid choice is to terminate.

I think the correct option is to print a stack trace, and abort the  
program.

> I'd like to be able to catch these.  I tend to run into a lot of fairly  
> benign sources of these, and they should be try-caught so that the user  
> doesn't get the boot unnecessarily.  Unnecessary crashing can lose user  
> data.  Maybe a warning message is sufficient: "hey that last thing you  
> did didn't turn out so well; please don't do that again." followed by  
> some automatic emailing of admins.  And the email would contain a nice  
> stack trace with line numbers and stack values and... I can dream huh.

You cannot be sure if your program is in a sane state.

> I might be convinced that things like segfaults in the /general case/  
> are fatal.  It could be writing to memory outside the bounds of an array  
> which is both not bounds-checked and may or may not live on the stack.  
> Yuck, huh.  But this is not the same as a null-dereference:
>
> Foo f = null;
> f.bar = 4;  // This is exception worthy, yes,
>              // but how does it affect unrelated parts of the program?

Again, this is a simple case.  There is also this case:

Foo f = new Foo();
... // some code that corrupts f so that it is now null
f.bar = 4;

This is not a "continue execution" case, and cannot be distinguished from  
the simple case by compiler or library code.

Philosophically, any null pointer access is a program error, not a user  
error, and should not be considered for "normal" execution.  Terminating  
execution is the only right choice.

-Steve


More information about the Digitalmars-d mailing list