Allowed operations on a possibly invalid pointer by strict interpretation of the C standard

Original question

(see "Edit: Updated Script")

This question can be duplicated in one way or another in a huge set of questions around the behavior of undefined pointers to objects that went out of scope, etc. But all the questions I found here for this thread are mostly specialized use cases, so I would like to turn the question upside down without asking if something is forbidden, but WHAT exactly is allowed?

To have a possible scenario: you have a function that takes a pointer - you don't know if it came from a (still) valid object. What operations are performed under all circumstances NOT undefined? What can have unspecified side conditions?

int * myFunc(const int * const A, int * B)
{
   ...
}

      

Edit: Updated Secenario

In the comments to the question and Matt McNabbs's answer , it was pointed out that UB went up anyway because an invalid pointer (s value) is being used during the call to the function in the script. So I'll modify the script a bit (following the example from Keith Thompsons answer ):

int *ptr = malloc(sizeof *ptr);
/* the value of ptr is now valid, possibly NULL */
if (ptr != NULL) 
{
    /* the value of ptr is valid and non-null */
    free(ptr);
    /* the value of ptr is now invalid */

    ... /* here operations in question */
}

      


List of permitted operations:

(To be completed and corrected by your answers and comments.)

  • Well defined: take the size of a pointer variable. For example.sizeof(ptr)

  • Well defined: take the size of the dereferenced pointer (if not void *

    ). For example. sizeof(*ptr)

    (see comments from EOF and Jonathan Leffler ).
  • Well defined: assigning a different (valid) value to a pointer (not to a reference variable!). For example.ptr = NULL;

  • Well defined: accessing a pointer view (example from Keith Thompson's answer )

    unsigned char rep[sizeof ptr];
    memcpy(rep, &ptr, sizeof ptr); /* ok, accesses the representation */
                                   /* but not the value */
    
          

Operations that are not defined according to the standard:

(To be completed and corrected by your answers and comments.)

These operations are often treated as if they were well defined with an invalid pointer, but were not well defined according to the standard:

  • Undefined: comparing a pointer value (even with a NULL pointer constant)
  • Undefined: converting to integral value

As with all undefined actions, you can get away with (ab) using pointers on many machines, but the C standard does not guarantee that you will succeed, and there are (or once were) machines where such pointer abuse will lead to a sharp reduction in programs.

For a general rule of thumb, see Keith Thompson's answer - and the extensive comments below.

+1


source to share


2 answers


Any use of an invalid pointer value has undefined behavior.

int *ptr = malloc(sizeof *ptr);
// the value of ptr is now valid, possibly NULL
if (ptr != NULL) {
    // the value of ptr is valid and non-null
    free(ptr);
    // the value of ptr is now invalid
    ptr; // UNDEFINED BEHAVIOR
}

      

Citation: N1570 6.2.4p2:

The value of a pointer becomes undefined if the object it points to (or just past) reaches the end of its life.

It is likely that the compiler will not generate code for the expression statement ptr;

; that is, of course, within the scope of undefined behavior.



Any operation on a pointer object that does not retrieve its value is (at least potentially) well defined:

sizeof ptr;  // ok, doesn't use the value
sizeof *ptr; // ok, doesn't use the value, only the type
ptr = NULL;  // ok

      

You can also access the view of the pointer object without accessing its value:

unsigned char rep[sizeof ptr];
memcpy(rep, &ptr, sizeof ptr); // ok, accesses the representation
                               // but not the value

      

although you cannot do with the result.

+4


source


This question is very broad. But to answer your specific scenario:

int * myFunc(const int * const A, int * B)

      



If this function was called with an invalid pointer value, it has already invoked undefined behavior, evaluating the invalid pointer value as part of preparing the function call.

All of your bullet points are not "well defined" correctly because after the UB has happened, the cat cannot be put back in the bag.

+1


source







All Articles