Where Exactly Does C++ Standard Say Dereferencing an Uninitialized Pointer Is Undefined Behavior

Is it undefined behavior in C++ to dereference an invalid pointer but not use the result?

Simply dereferencing a pointer that has not been allocated or is marked as read-only can cause a hardware exception in the CPUs memory management unit. So even if you don't use whatever garbage value would be returned by dereferencing a pointer that contains a random value, there is no guarantee the CPU would return from such an event.

However, according to the ISO C++11 Standard a pointer that is declared uninitialized must have a singular value. So the value of an uninitialized pointer is not undefined as in it is not garbage.

However the Standard states that most operations on such a singular value pointer are undefined with the exception of overwriting the singular value with a non singular value:

24.2.1 In general [ iterator.requirements.general ]

5 [ Example: After the declaration of an uninitialized pointer x (as with int* x;), x must always be assumed to have a singular value of a pointer. — end example ] Results of most expressions are undefined for singular values; the only exceptions are destroying an iterator that holds a singular value, the assignment of a non-singular value to an iterator that holds a singular value, and, for iterators that satisfy the DefaultConstructible requirements, using a value-initialized iterator as the source of a copy or move operation. [ Note: This guarantee is not offered for default initialization, although the distinction only matters for types with trivial default constructors such as pointers or aggregates holding pointers. — end note ] In these cases the singular value is overwritten the same way as any other value. Dereferenceable values are always non-singular.

The segmentation fault error that I cannot understand

Here's a step-by-step breakdown of what your code is doing:




int *a;
int *b;

This declares two pointers to int named a and b. It does not initialize them. That means that their values are unspecified, and you should expect them to be complete garbage. You can think of them as "wild" pointers at this moment, which is to say that they don't point to valid objects, and dereferencing them will cause Undefined Behavior and introduce a plethora of weird bugs, if not a simple crash.




int c=12;

This creates a simple local variable c of type int, which is initialized, with a value of 12. If you hadn't initialized it, as in int c; then it would also be full of garbage.




a=&c;

This snippet sets the pointer a to point to c, which is to say that the address of c is assigned to a. Now a is no longer uninitialized, and points to a well-defined location. After this, you can safely dereference a and be assured that there is a valid int at the other end.




*b=*b;

Here, you are dereferencing b, which means that you are reaching into your programs memory to grab whatever is pointed to by b. But b is uninitialized; it is garbage. What is it pointing to? Who knows? To read from the address it points to is like Russian roulette, you might kill your program immediately if you get really unlucky and the Operating System or runtime environment notices you doing something that's obviously wrong. But you also might get away with it, only for weird and unpredictable bugs to emerge later. This weirdness and unpredictability is why a good C++ programmer avoids Undefined Behavior at all costs, and ensures that variables are initialized before they are used, and makes sure that pointers are pointing to valid objects before dereferencing them.

Why does there appear to be a difference depending on a=&c;?

As to why your program apparently crashes or doesn't crash depending on how you initialize the other pointer, the answer is that it doesn't matter. In both cases, you're causing Undefined Behavior; you are breaking the language's rules and you should not expect the language to behave correctly for you thereafter, and all bets are off.

Weird bug in pointers

This exhibits undefined behavior:

unsigned int* a; 
*a= 4294967295; //set to max val (4 bytes)

The pointer variable a is never initialized to anything, so it points to a random memory address. Writing anything to that random garbage address (typically) causes a segmentation fault. It's just coincidence that adding another variable changes the behavior (due to a change in memory layout of the program).

In C++, does Initializing a reference or pointer with itself cause UB?

// namespace scope
int *p1 = p1; // p1 0 initialized, `p1` is a null ptr, not UB?

Standard is ambiguous regarding this case, but "not UB" could reasonably be argued due to the static initialisation that precedes the dynamic initialisation. On the other hand standard implies that lifetime of the object hasn't started yet.

More details about the ambiguity here: If a global variable is initialized twice (statically, then dynamically), which initialization starts its lifetime?

// block scope
int *p2 = p2; // pointer to garbage location. has UB ?

Yes. Unlike in the case of static storage duration, the automatic object lacks the static initialisation stage, and has an indeterminate value before it is initialised. You're using that indeterminate value for the initialisation and the behaviour of the program is unambiguously undefined.

// block scope
int *p3 = p2; // Also has UB ?

Behaviour is already undefined in initialisation of p2. But let's say p2 was an indeterminate value without previous UB:

int *p2;
int *p3 = p2;

The behaviour of this example is undefined as well.

Note that these have little to do with the object being a pointer. This applies to objects of nearly all types.


A reference must be initialised to refer to a valid object or function. Hence all three of these:

// namespace scope
int &r1 = r1; // r1 0 initialized, `r1` references 0, not UB?

// block scope
int &r2 = r2; // reference to intermediate value. has UB ?
int &r3 = r2; // Also has UB ?

make the program ill-formed.

I get a warning for a local variable, but not a global one.

I believe that the compiler is non-conforming in its failure to diagnose r1. Clang does diagnose it, as required. Furthermore, clang's UB-sanitizer detects it at runtime.

At what point does dereferencing the null pointer become undefined behavior?

Yes it is undefined behavior, because the spec says that an "lvalue designates an object or function" (at clause 3.10) and it says for the *-operator "the result [of dereferencing] is an lvalue referring to the object or function to which the expression points" (at clause 5.3.1).

That means there is no description for what happens when you dereference a null pointer. It's simply undefined behavior.

Is initializing a pointer declarator with an invalid pointer undefined behavior?

You’ve all but answered this yourself: it’s implementation defined, not undefined, in C++. The standard says just what you quoted (which I found by consulting the appropriate index). It doesn’t matter whether it’s initialization: the lvalue-to-rvalue conversion on the pointer object explicitly constitutes a use.



Related Topics



Leave a reply



Submit