Is Storing an Invalid Pointer Automatically Undefined Behavior

Is storing an invalid pointer automatically undefined behavior?

I have the C Draft Standard here, and it makes it undefined by omission. It defines the case of ptr + I at 6.5.6/8 for

  • If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.
  • Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object.

Your case does not fit any of these. Neither is your array large enough to have -1 adjust the pointer to point to a different array element, nor does any of the result or original pointer point one-past-end.

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.

Is using an invalid pointer value legal in C?

It's undefined behavior in C as well because on certain architectures, loading an invalid pointer into a register triggers a hardware fault.

See Is storing an invalid pointer automatically undefined behavior?

Is it undefined behavior to form a pointer range from a stack address?

This is allowed, the behavior is defined and both begin and end are safely-derived pointer values.

In the C++ standard section 5.7 ([expr.add]) paragraph 4:

For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

When using C a similar clause can be found in the the C99/N1256 standard section 6.5.6 paragraph 7.

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.


As an aside, in section 3.7.4.3 ([basic.stc.dynamic.safety]) "Safely-derived pointers" there is a footnote:

This section does not impose restrictions on dereferencing pointers to memory not allocated by ::operator new. This maintains the ability of many C++ implementations to use binary libraries and components written in other languages. In particular, this applies to C binaries, because dereferencing pointers to memory allocated by malloc is not restricted.

This suggests that pointer arithmetic throughout the stack is implementation-defined behavior, not undefined behavior.

Is fetching the value of an invalid pointer undefined or implementation defined behaviour in C?

Expanding on Andrew Henle's answer:

From the C99 Standard, 6.2.4:

An object has a storage duration that determines its lifetime. There are three storage durations: static, automatic, and allocated. Allocated storage is described in 7.20.3. […] The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

Then in 7.20.3.2: the standard goes on describing malloc(), calloc() and free(), mentioning that

The free function causes the space pointed to by ptr to be deallocated.

In 3.17.2:

indeterminate value

either an unspecified value or a trap representation

In 6.2.6.1.5:

Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. […] Such a representation is called a trap representation.

Since the pointer becomes indeterminate, and an indeterminate value can be a trap representation, and you have a variable which is an lvalue, and reading an lvalue trap representation is undefined, therefore yes, the behavior may be undefined.

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.

Can I store a pointer to non-existing data without invoking undefined behavior?

Yes, there is NO undefined behavior in your code. What you get are two dangling pointers, i.e. x and y. They are perfectly fine if you don't dereference them (or free them again), but they represent a major source of errors in C-style code.

Is it safe to keep a pointer out-of-bounds without dereferencing it?

Moving pointer to one element past the last element is allowed, but moving further or moving before the first element is not allowed.

Quote from N1570 6.5.6 Additive operators (point 8):

When an expression that has integer type is added to or subtracted from a pointer, the
result has the type of the pointer operand. If the pointer operand points to an element of
an array object, and the array is large enough, the result points to an element offset from
the original element such that the difference of the subscripts of the resulting and original
array elements equals the integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of
the array object, provided they exist. Moreover, if the expression P points to the last
element of an array object, the expression (P)+1 points one past the last element of the
array object, and if the expression Q points one past the last element of an array object,
the expression (Q)-1 points to the last element of the array object. If both the pointer
operand and the result point to elements of the same array object, or one past the last
element of the array object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined. If the result points one past the last element of the array object, it
shall not be used as the operand of a unary * operator that is evaluated.

Clarification on behaviour of comparing invalid pointers

Am I to understand that this is exactly one past the end of the array or that all pointers past the end of the array are valid.

Only a pointer one-past-the-array or one-past-the-object is valid (although you cannot dereference such a pointer). Pointers after that cannot be constructed, because pointer arithmetic has undefined behavior past this point.

The note above would have me believe that a pointer that does not point to an instantiated object is automatically invalid, since it is pointing to potentially unallocated memory.

The pointer doesn't need to point to an actual object if it is the one-past-end pointer. However such a pointer cannot be dereferenced. The pointers to the array/object, including the one-past-the-end pointer become invalid as soon as the storage duration of the object/array ends.

Which to me would suggest that if a pointer does not point to an array element or an object that has not reached the end of its lifetime, it is invalid.

The one-past-the-end pointers are considered a hypothetical element of the (hypothetical) array for the quoted clauses, see the note under the section referencing [basic.compound].

Would this be undefined behaviour if elem is not in the interval [arr_first, arr_last] since there is no guarantee elem points to anything?

Assuming arr_first is the first element of an array and arr_last the last element of the array, your function has unspecified behavior if elem doesn't point into the range arr_first to arr_last+1 inclusive.

This doesn't mean that it has undefined behavior, just that the return value of the function may be completely arbitrary.

However, trying to form e.g. a pointer arr_last+2 to pass to the function already has undefined behavior itself, since pointer arithmetic is only defined as long as one stays within the bounds of the array (or one-past-the array).

Which in turn invalidates the existence of this function since I can't guarantee its (expected) false results are defined?

The function as written is technically not useful, although I suppose it will work more or less as expected in practice most of the time. It is a much better approach to validate indices into the array, rather than pointers.

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.



Related Topics



Leave a reply



Submit