Alexey Frunze Alexey Frunze - 1 month ago 11
C Question

realloc(), lifetime and UB

There's a recent CppCon2016 talk My Little Optimizer: Undefined Behavior is Magic, which shows the following code (26 mins into the talk). I beautified it a bit:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int* p = malloc(sizeof(int));
int* q = realloc(p, sizeof(int));
*p = 1;
*q = 2;
if (p == q)
{
printf("%d %d\n", *p, *q);
}
return 0;
}


The code has undefined behavior (p becomes invalid after realloc() even if realloc() returns the same pointer) and when compiled may print not only "2 2", but also "1 2".

What about a slightly modified version of the code?:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
int* p = malloc(sizeof(int));
uintptr_t ap = (uintptr_t)p;
int* q = realloc(p, sizeof(int));
*(int*)ap = 1;
*q = 2;
if ((int*)ap == q)
{
printf("%d %d\n", *(int*)ap, *q);
}
return 0;
}


Why can I still get "1 2" printed? Does the integer variable ap also somehow become invalid or "tainted"? If so, what's the logic here? Shouldn't ap become "decoupled" from p?

P.S. Added the C++ tag back. This code can be trivially rewritten as C++ and the same question applies in C++ as well. I'm interested in both C and C++.

Answer

The latest C standards leave the issue ambiguous. N2090 states that the DR260 Committee Response

has not been incorporated in the standard text, and it also leaves many specific questions unclear...

So, it's reasonable to assume that there's, in fact, undefined behavior, even if it's not explicitly documented in the standard proper.