Mark A.
Mark A.

Reputation: 601

Allowed operations on an possibly invalid pointer by the strict interpretation of the C Standard

Original Question

(please see "Edit: Updated scenario")

This question might be a duplicate in one or another way to a huge collection of questions around undefined behavior of pointers to objects that gone out of scope etc. But all questions I found here to this topic are mostly specialized use cases. So I would like to spin the question upside down, not 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. Which operations are under all circumstances NOT undefined behavior? Which might have unspecified side conditions?

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

Edit: Updated Secenario

In the comments to the question and Matt McNabbs answer it was pointed out that UB has risen most likely anyway, as an invalid pointer(s value) is used during call the function in the scenario. Therefore I will change the scenario a little (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 allowed operations:

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

Operations that are not well-defined according to the standard:

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

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

As with all undefined behaviour, you may get away with (ab)using the pointers on many machines, but the C Standard does not guarantee that you will get away with and there are (or once were) machines where such abuse of a pointer would lead to programs failing dramatically.

For the general rule, see Keith Thompson's answer — and the extensive comments below.

Upvotes: 1

Views: 186

Answers (2)

M.M
M.M

Reputation: 141586

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

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

If this function were called with an invalid pointer value then it already caused undefined behaviour by evaluating the invalid pointer value as part of preparing to call the function.

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

Upvotes: 1

Keith Thompson
Keith Thompson

Reputation: 263277

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 indeterminate when the object it points to (or just past) reaches the end of its lifetime.

It's likely that a compiler will generate no code for the expression statement ptr;; that is, of course, within the bounds of undefined behavior.

Any operation on the pointer object that doesn't 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 representation 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

though there's not much you can do with the result.

Upvotes: 5

Related Questions