Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is converting an integer to a pointer always well defined?

Is this valid C++?

int main() {
    int *p;
    p = reinterpret_cast<int*>(42);
}

Assuming I never dereference p.

Looking up the C++ standard, we have

C++17 §6.9.2/3 [basic.compound]

3 Every value of pointer type is one of the following:

  • a pointer to an object or function (the pointer is said to point to the object or function), or
  • a pointer past the end of an object ([expr.add]), or
  • the null pointer value ([conv.ptr]) for that type, or
  • an invalid pointer value.

A value of a pointer type that is a pointer to or past the end of an object represents the address of the first byte in memory ([intro.memory]) occupied by the object or the first byte in memory after the end of the storage occupied by the object, respectively. [ Note: A pointer past the end of an object ([expr.add]) is not considered to point to an unrelated object of the object's type that might be located at that address. A pointer value becomes invalid when the storage it denotes reaches the end of its storage duration; see [basic.stc]. — end note ] For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), a pointer past the end of the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical array element n of x and an object of type T that is not an array element is considered to belong to an array with one element of type T.

p = reinterpret_cast<int*>(42); does not fit into the list of possible values. And:

C++17 §8.2.10/5 [expr.reinterpret.cast]

A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. [ Note: Except as described in 6.7.4.3, the result of such a conversion will not be a safely-derived pointer value. — end note ]

C++ standard does not seem to say more about the integer to pointer conversion. Looking up the C17 standard:

C17 §6.3.2.3/5 (emphasis mine)

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.68)

and

C17 §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. If such a representation is produced by a side effect that modifies all or any part of the object by an lvalue expression that does not have character type, the behavior is undefined.50) Such a representation is called a trap representation.

To me, it seems like any value that does not fit into the list in [basic.compound] is a trap representation, thus p = reinterpret_cast<int*>(42); is UB. Am I correct? Is there something else making p = reinterpret_cast<int*>(42); undefined?

like image 485
Ayxan Haqverdili Avatar asked Feb 10 '20 09:02

Ayxan Haqverdili


People also ask

How do you define an integer to a pointer?

The syntax of declaring a pointer is to place a * in front of the name. A pointer is associated with a type (such as int and double) too. Naming Convention of Pointers: Include a "p" or "ptr" as prefix or suffix, e.g., iPtr, numberPtr, pNumber, pStudent.

Can an integer be a pointer?

A pointer holds a memory address, from 0 to the upper limit of your memory. So in math terms, a pointer could be considered a non-negative integer.

Can you cast an int to a pointer?

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

What will happen if an integer number is added to a pointer?

Pointer arithmetic and arrays. Add an integer to a pointer or subtract an integer from a pointer. The effect of p+n where p is a pointer and n is an integer is to compute the address equal to p plus n times the size of whatever p points to (this is why int * pointers and char * pointers aren't the same).


2 Answers

This is not UB, but implementation-defined, and you already cited why (§8.2.10/5 [expr.reinterpret.cast]). If a pointer has invalid pointer value, it doesn't necessarily mean that it has a trap representation. It can have a trap representation, and the compiler must document this. All you have here is a not safely-derived pointer.

Note, that we generate pointers with invalid pointer value all the time: if an object is freed by delete, all the pointers which pointed to this object have invalid pointer value.

Using the resulting pointer is implementation defined as well (not UB):

[...] if the object to which the glvalue refers contains an invalid pointer value ([basic.stc.dynamic.deallocation], [basic.stc.dynamic.safety]), the behavior is implementation-defined.

like image 65
geza Avatar answered Dec 27 '22 19:12

geza


The example shown is valid c++. On some platforms this is how you access "hardware resources" (and if it's not valid you have found a bug/mistake in standard text).

See also this answer for a better explanation.


Update: The first sentence of reinterpret_cast as you quote yourself:

A value of integral type or enumeration type can be explicitly converted to a pointer.

I recommend you stop reading and rest yourself at this point. The rest of just a lot details including possible implementation specified behavior, etc. That doesn't make it UB/invalid.

like image 43
darune Avatar answered Dec 27 '22 18:12

darune