3

While reading the answers to this SO question, I learned that out-of-bounds pointer arithmetic is undefined. Indeed, according to C99 6.5.6 paragraph 8

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.

Does freeing that object invalidate that guarantee? 7.20.3.2 "The Free Function" Doesn't seem to mention it, simply mentioning that "the space is deallocated". Since 6.5.6 specifically mentions overflow, it seems like an integer overflow issue, which free wouldn't affect. Is arithmetic on a pointer to an object an act of "referring to it"?

In other words, is:

char *foo = malloc(10);
free(foo);
foo++;

Undefined? Or is the usage of "overflow" a different one?

Community
  • 1
  • 1
Dave
  • 10,964
  • 3
  • 32
  • 54
  • 1
    After you free the pointer, it doesn't point to an array anymore. That rules out "point to elements of the same array object", when it doesn't point to anything at all. – Bo Persson Jul 31 '12 at 22:41

2 Answers2

5

C99 §6.2.4 says:

The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime.

§7.20.3 describes the lifetime of allocated objects, as created by malloc():

The lifetime of an allocated object extends from the allocation until the deallocation.

So, formally speaking, the value of the pointer foo becomes indeterminate after the free(), and therefore can no longer be said to point to any object. The behaviour of the increment is therefore undefined.

caf
  • 233,326
  • 40
  • 323
  • 462
  • 1
    So, even printing the pointer is undefined? Could a valid C runtime walk all memory NULL-ing all of the pointers which used to point to an object upon its freeing? – Dave Jul 31 '12 at 06:05
  • 1
    @Dave: Well, the *value* becomes indeterminate, so if you print it using the pointer value (with `%p`, or by casting it to an integer and printing that) then it's undefined. But I don't believe the underlying representation becomes indeterminate - if you access it as an array of `unsigned char` then it should remain the same. So the bytes that make up the pointer remain the same, but the *meaning* of them, as a pointer, becomes indeterminate. – caf Jul 31 '12 at 06:39
  • 2
    You cannot even rely on the bytes that make up the pointer remaining the same. The C standard permits a great deal of latitude in this regard. Consider an implementation in which a process must manage its own memory, because the hardware does not support virtual memory. In this implementation, a pointer may be implemented as an address of a structure in memory with additional information, such as disk locations of actual data. The “value” of a pointer would include such additional information. (Continued below.) – Eric Postpischil Jul 31 '12 at 08:38
  • E.g., note that the printf format “P” prints an implementation-defined sequence of characters, not merely an address. In an implementation with a complicated memory-based pointer scheme, printing a pointer with the “P” format would require reading memory and printing some of the information there. When you free an object in such an implementation, and especially when you allocate another, these data structures in memory will change, and the value of the old pointer will be lost. – Eric Postpischil Jul 31 '12 at 08:39
1

Performing arithmetic on an invalidated pointer invokes undefined behavior.