Does dereference a NULL pointer guarantee to crash a program in C/C++?
Asked Answered
S

5

9

I come across this wired code and it's not crashing.

#include <stdio.h>
struct s
{
    char* c;
    char* c2;
};

int main()
{
    struct s* p = NULL;
    printf("%d\n", &(p->c));
    printf("%d\n", &p->c2);
    printf("%d\n", &(*p).c2);
    return 0;
}

Output:

0
4
4

I have several question comes to me I cannot answer:

  1. Does NULL pointer always equal to 0 in c/c++?

  2. What happen if 0 happen to be an address of a variable?

  3. It seems the outputs are offset addresses of members of the struct. How does this get calculated. I mean p->c is the address of c which doesn't exist because p == NULL. How come you can get address of the address of c by &p->c if the address of c doesn't exist?

  4. Does dereference a NULL pointer guarantee to crash a program in C/C++?(Let's assume in system)

Simms answered 3/4, 2014 at 19:48 Comment(2)
In C++ null is replaced with 0.Phagocytosis
All 3 printf() are Undefined Behavior (UB). "%d" is the wrong matching specifier for a pointer. Use "%p".Reiss
G
16

No, dereferencing a null pointer doesn't guarantee a crash.

For one thing, in many cases, the compiler is able to optimize out the dereference operation. in your case, &(p->c) nominally dereferences a null pointer, but you then take the address of the result (after selecting a member of the pointed-to structure). Presumably the compiler replaces the entire expression by a number, which is the offset of the members within the structure. (There's no guarantee that a null pointer refers to address 0, or that it will be optimized in this manner, but it happens to do so on your system.)

This is the basis of a common implementation of the standard offsetof macro. It can't be implemented in portable standard C or C++, but implementations commonly use system-specific tricks like this -- which is perfectly valid as long as it yields the correct result on that system.

Second, even if you actually dereference a null pointer, the behavior is undefined. This might mean that your program crashes, but as far as the language standard is concerned it can do literally anything.

There have been systems in the past (and there probably still are) where a null pointer refers to address 0, and the system's memory map is set up so that address 0 is a valid memory address that happens to contain a 0 value. On such a machine, for example, a null pointer acts like a pointer to an empty '\0'-terminated character string. This led to a flurry of bug fixes when code that worked on such systems, and which unintentionally depended on that behavior, was ported to newer systems with stronger memory protection. (I think this may have been the transition from the 68K-based Sun 3 to the SPARC-based Sun 4, but I'm not sure of that.)

For more information on null pointers, see section 5 of the comp.lang.c FAQ. Most of it applies to C++ as well.

Gerhard answered 3/4, 2014 at 19:59 Comment(0)
W
2

You aren't actually dereferencing the pointer. That is why the code isn't crashing. What the code does is to get the offset of the struct members. The first member is at the offset of 0 bytes and the second at 4 bytes.

The c standard doesn't guarantee that NULL pointer is defined as 0, it is implementation defined. ( 201x: 7.19)

Winnebago answered 3/4, 2014 at 19:51 Comment(3)
As my understanding, p->c is dereferencing it and &(p->c) is to get address.Simms
@Simms You have to look at the expression as a whole, it doesn't dereference.Winnebago
p->c is defined as (*p).c, see [expr.ref]/2. This is a dereference operation: the expression of type "pointer to T" is converted to expression of type T. I guess you are conflating "dereference" with "dereference and perform lvalue-to-rvalue conversion on the result".Cuprum
V
0

In C++ the null pointer is always 0.

In C the NULL pointer could be something else than 0, but I've never seen any system like this.

On all modern systems that use virtual memory dereferencing a null pointer will crash. But you didn't do that in your program BTW.

Vinaya answered 3/4, 2014 at 19:53 Comment(1)
A literal 0 is a null pointer constant. That doesn't imply that a null pointer is represented as all-bits-zero.Gerhard
H
0
  1. NULL is always zero: http://www.cplusplus.com/reference/cstring/NULL/.

A null-pointer constant is an integral constant expression that evaluates to zero (like 0 or 0L), or the cast of such value to type void* (like (void*)0).

2. This is highly unlikely, partially due to virtual memory, and might be prevented in the compiler. 3. The compiler might implement structs with offsets. Also, you are not dereferencing the pointer, only taking the address.

Huldahuldah answered 3/4, 2014 at 19:53 Comment(0)
J
0
  1. Sure, NULL is always 0. Unless you define it to be something else.
  2. I think that now mapping a page at 0 is not allowed, but if it is allowed, you can have a variable at address 0.
  3. You see, you never actually accessed the variables pointed to by p. You just want their addresses. They can be calculated from p. A pointer takes 4 bytes (on your platform), so we know that first pointer in the structure's offset is 0, second is 4, etc.
Jeseniajesh answered 3/4, 2014 at 19:54 Comment(1)
The macro NULL expands to the constant 0, but that doesn't mean that a null pointer refers to address zero in memory. See section 5 of the comp.lang.c FAQ; most of it also applies to C++.Gerhard

© 2022 - 2024 — McMap. All rights reserved.