40

I'm wondering about what the C++ standard says about code like this:

int* ptr = NULL;
int& ref = *ptr;
int* ptr2 = &ref;

In practice the result is that ptr2 is NULL but I'm wondering, is this just an implementation detail or is this well defined in the standard?
Under different circumstances a dereferencing of a NULL pointer should result in a crash but here I'm dereferencing it to get a reference which is implemented by the compiler as a pointer so there's really no actual dereferencing of NULL.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 5
    http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-behav is providing a very good answer to this problem. – pmr Apr 28 '10 at 08:32
  • Linked duplicate: [Dereferencing a NULL pointer to a reference which is unused; Is this also “Undefined Behaviour”?](http://stackoverflow.com/q/40216965/514235) – iammilind Oct 24 '16 at 11:22

5 Answers5

52

Dereferencing a NULL pointer is undefined behavior.

In fact the standard calls this exact situation out in a note (8.3.2/4 "References"):

Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.


As an aside: The one time I'm aware of that a NULL pointer can be "dereferenced" in a well-defined way is as the operand to the sizeof operator, because the operand to sizeof isn't actually evaluated (so the dereference never actually occurs).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 6
    And indeed if it's an operand of `typeid` and if it's a null pointer of type `PolymorphClass*`, then it's dereferenced *and* evaluated. Still it's well-defined (throwing `bad_typeid`). I do really not like that special `typeid` treatment. – Johannes Schaub - litb Apr 28 '10 at 16:42
  • 3
    It's unfortunate about not allowing a NULL reference. It exhibits some cool properties, but I guess it just complicates code. :( If preconditions were available and code could be better verified, NULL references could be used safely. – Adrian May 24 '13 at 22:58
  • 1
    sizeof() is an operator on the type of a variable, not the value. NULL pointers do have types. – jforberg Jun 09 '15 at 17:40
  • @jforberg: I don't see anyone here claiming otherwise? – Lightness Races in Orbit Aug 04 '15 at 17:48
  • 1
    @Lightness No-one is. I'm just clarifying. – jforberg Aug 05 '15 at 13:12
5

Dereferencing a NULL pointer is explicitly undefined behaviour in the C++ standard, so what you see is implementation specific.

Copying from 1.9.4 in the C++0x draft standard (similar to previous standards in this respect):

Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. - end note]

Gorpik
  • 10,940
  • 4
  • 36
  • 56
  • 3
    It's funny, because nobody has been able to show where in the standard dereferencing a null pointer is explicitly made UB. The standard is incorrect here. – curiousguy Nov 29 '11 at 02:53
  • 1
    @curiousguy: 8.3.2.5 once again alludes to the fact that dereferencing a null pointer is undefined. But you are right, it does so as if it was explained elsewhere. Anyway, 1.3.13 explains that any behaviour that is not explicitly defined is considered undefined, so this can be the case. – Gorpik Nov 29 '11 at 10:39
  • 2
    "8.3.2.5" BTW, it's spelled 8.3.2/5. There is no 8.3.2.5 section. "_any behaviour that is not explicitly defined is considered undefined_" You are right: dereferencing a pointer is only defined if the pointer points to an object. But it would be slightly more clear if the standard was explicit about that - and less electronic ink would be spent on this non-issue. – curiousguy Nov 29 '11 at 11:19
  • 3
    Notes are non-normative. This note was in fact removed as the result of [DR 1102](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1102) with the stated reasoning being that it was not undefined behaviour to dereference a null pointer. – M.M Oct 10 '14 at 00:54
1

Dereferencing a NULL pointer is undefined behaviour. You should check if a value is NULL before dereferencing it.

Goz
  • 61,365
  • 24
  • 124
  • 204
1

For completeness, this: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 talks specifically about this issue.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • Hum... very creative thinking. So, calling a member function with a null `this` is allowed!!! I wonder what they were smoking. Anyway, 7 years latter nothing has been done in the direction of this craziness. – curiousguy Nov 29 '11 at 03:03
  • Actually it isn't, according to http://stackoverflow.com/a/2474021/399317 (because of lvalue-to-rvalue conversion) – Kos Aug 23 '12 at 17:49
  • Interesting that the #232 uses division by zero as an example of UB, when many C++ implementations implicitly incorporate IEEE-754, which defines the effects of division by positive and negative zero. *Integer* division by zero is UB, but the example doesn't specify that. – supercat Oct 25 '16 at 01:47
  • That you have to use the word "many" is an example of UB. – Jeremy Dec 02 '16 at 10:05
-2
int& ref = *ptr;

The above statement doesn't actually dereference anything. So there's no problem until you use the ref (which is invalid).

valdo
  • 12,632
  • 2
  • 37
  • 67
  • 4
    Nonsense. unary `*` is **actually** the dereference operator. It **actually** performs the dereference operation. – curiousguy Nov 29 '11 at 02:54
  • 1
    @curiousguy: I advise you to compile this and see the code in the disassembler. The reference `ref` is essentially a pointer, so the above statement is just a pointer assignment behind the scenes. – valdo Nov 29 '11 at 15:20
  • 2
    You misunderstand me. I do not care what assembly code is generated. What is `*ptr`, according you? – curiousguy Nov 29 '11 at 16:23
  • 1
    @curiousguy: `*ptr` is a dereferencing indeed. But this doesn't mean that it is actually done (evaluated). For instance, you can write `sizeof(*ptr)` and the expression `*ptr` is **guaranteed** not to be evaluated during run-time. – valdo Nov 29 '11 at 20:23
  • 4
    Indeed, the operand of `sizeof` is not evaluated: you may write `sizeof(1./0.)` without any problem. That's because `sizeof` is only concerned about the type of its operand. OTOH, the operand of `&` is evaluated, otherwise what would address-of apply to? – curiousguy Nov 30 '11 at 03:21
  • My potentially flawed understanding: This is (probably in practice) not a dereference according to the output assembly, so you will not see a segfault or a valgrind error from this line alone. But it is a dereference according to the compiler's understanding of undefined behavior, so the compiler is allowed to output a totally broken program if it chooses to. – Jack O'Connor Apr 25 '20 at 23:28