4

Say we have:

char *a = malloc(sizeof(char*));    
char *b = realloc(a,sizeof(char*));

Can we safely say that b does not alias with a? The realloc reference page says that

The original pointer ptr is invalidated and any access to it is undefined behavior (even if reallocation was in-place).

So can I mark b as not aliasing a as we cannot legally access a anymore? However this could result in a questionable optimization where the below branch would be eliminated:

if (a == b)
  something..

Based on my understanding, the comparison of a == b itself would be UB so is this a technically correct optimization?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
MIA
  • 130
  • 7
  • Please could you supply the link to the reference – Ed Heal Dec 26 '17 at 07:09
  • 1
    yes, `realloc` can return a different address. When that happens, the old one is freed by `realloc` and can safely ignore it. However, if `realloc`fails, it will return `NULL` and the old address will still be valid. – Pablo Dec 26 '17 at 07:09
  • But `realloc` can also return the *same* address (and still grow the memory zone...) – Basile Starynkevitch Dec 26 '17 at 07:09
  • @EdHeal http://en.cppreference.com/w/c/memory/realloc – MIA Dec 26 '17 at 07:11
  • And if realloc does fail then you had better have kept the old address (a in your case) because otherwise you have no way to recover it. so don't ever do "a = realloc(a, newSize);" – SoronelHaetir Dec 26 '17 at 07:13
  • @Pablo If it returns NULL old address will certainly be valid but since b is NULL it will not alias a right? i am more interested in the case where realloc is done in-place – MIA Dec 26 '17 at 07:19
  • @PratikBhatu I don't know what you mean by "alias", don't know where you've got this term. In any case, you are using the term wrong. `realloc` returns a pointer to a new object with the new size requirements. This object **may** be in the same memory position as the old one, it also may be in another position. That's all you need to know. – Pablo Dec 26 '17 at 18:36
  • @PratikBhatu In any case you should never do stuff like this: `a = realloc(a, newsize)` but declare a new pointer `tmp` and do `tmp = realloc(a, newsize);`. Afterwards check for `tmp == NULL`. If that's the case, `realloc` fail and `a` points to a valid region. If `tmp != NULL` then you can safely do `a = tmp;` and keep working. – Pablo Dec 26 '17 at 18:39
  • @Pablo I had originally tagged the question with compiler-construction too, but a mod removed that tag. I mean aliasing from a compiler optimization point of view [wiki-link](https://en.wikipedia.org/wiki/Alias_analysis). And yes, i understand why I should never do a = realloc(a,..). Thank you! – MIA Dec 27 '17 at 04:49
  • @PratikBhatu ok, that make sense. I didn't know the term *alias* in that context. – Pablo Dec 27 '17 at 04:52

2 Answers2

3

After freeing, the value of a is indeterminate.

n1570-§6.2.3 (p2):

[...] If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

If this indeterminate value becomes trap representation the comparison a == b will cause an undefined behavior.

Note that the lifetime of the object pointed to by pointer reaches its end when the pointer is passed to free.

Further readings:
1. Why isn't a pointer null after calling free?
2. A dangling pointer is indeterminate.

alk
  • 69,737
  • 10
  • 105
  • 255
haccks
  • 104,019
  • 25
  • 176
  • 264
2

Based on my understanding, the comparison of a == b itself would be UB..

Well, yes.

Regarding the "why" part, as mentioned in haccks's answer, after a pointer has been free()d, the object it points to reaches the end of it's lifetime, thus making the pointer value indeterminate. So, any further use (read) of the pointer itself would be unspecified behavior at best and any attempted usage of the address pointed to by it, would invoke undefined behavior.

So, technically, the optimization you expect, would be correct and would be a must to make the code exhibit a defined behavior, as the code is incorrect to start with. Do not expect the compiler to correct your code, it may not.

That said, regarding

Can we safely say that "b" does not alias with "a"?

I'm not very clear on what ground you used the alias here, but just to be sure, the official wording, from C11, chapter §7.22.3.5,

P2:

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. [...]

P3:

[...] If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

and, P4:

The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • How the comparison is valid here after `a` is freed? – haccks Dec 26 '17 at 07:12
  • @PascalCuoq Yes, I see that now clearly after haccks's answer. The object it points to does not exist anymore, so the pointer is indeterminate. I'll update accordingly and thanks for the comment. – Sourav Ghosh Dec 26 '17 at 07:42
  • 1
    @PascalCuoq; Man! I was looking upto that post to backup my answer because I remember I read somewhere about this where you refer this post once. Thanks a ton. – haccks Dec 26 '17 at 07:44
  • @haccks Now both of us got to bookmark that one. :) – Sourav Ghosh Dec 26 '17 at 07:48