6 ms·
int main() { int *p = (int*)malloc(sizeof(int)); int *q = (int*)realloc(p, sizeof(int)); *p = 1; *q = 2; if (p == q)
by jackweirdy 11y ago
int main() {
int *p = (int*)malloc(sizeof(int));
int *q = (int*)realloc(p, sizeof(int));
*p = 1;
*q = 2;
if (p == q)
printf("%d %d\n", *p, *q);
}
$ clang -O realloc.c ; ./a.out
1 2
That's about as eyebrow-raising as you can get!
- chrisseaton 11y agoI would have thought that the optimiser would see that p and q are aliased after the `p == q` condition and so not use the written values after that. But yeah aliasing that the compiler can't see (if it's not doing a stamp based on the equality condition) I can understand why that's undefined as what else would you want the compiler to do? Treat all memory as volatile? That would destroy performance.
- derefr 11y agoMy default answer would be "disallow usage of p after the realloc." Which is why I like Rust, I guess.
- chrisseaton 11y agoBut I believe the compiler has no knowledge of the semantics of these functions to do that.
- gpderetta 11y agoThe behaviour of those functions is defined by the standard. The compiler is aware that realloc invalidates its pointer parameter.
- masklinn 11y ago> The compiler is aware that realloc invalidates its pointer parameter. According to the standard, realloc doesn't invalidate its pointer parameter, since it can return the existing pointer (if the resizing could be done in-place) and can not touch the existing pointer (if the reallocation fails).
- gpderetta 11y agoAccording to the latest C standard draft that I could find, the semantics of realloc are that it deallocates the old object and allocates a new one. Of course, as an intended optimization, the new pointer value might have the same value as the old one, but that's not part of the semantics. The only case in which the old pointer is not invalidated is if realloc fails. As far as I know, in practice, at least with GCC, but likely clang as well, the compiler doesn't tracks the invalidation, but it simply assumes that any non null pointer returned by realloc (or any allocation function in fact) does not alias any other existing pointer in the program.
- mhogomchungu 11y agoThe pointer is invalidated only if the object is moved and the object is not always moved and hence the pointer is not always invalidated. http://pubs.opengroup.org/onlinepubs/7908799/xsh/realloc.html http://pubs.opengroup.org/onlinepubs/7908799/xsh/realloc.htm...
- derefr 11y agoDo note that I wasn't proposing to invalidate the memory-address handle contained in p; but rather to lexically invalidate p itself, such that it would no longer be legal for it to occur as an rvalue until a new value was assigned to it as an lvalue. You know, like Rust.
- shultays 11y agoIn this case it is easy to see that p is no longer valid but what about other pointers that points to the same location but not trivially visible for compilers? It won't be possible without run time checks or memory system like the one in rust.
- lmm 11y ago> It won't be possible without run time checks or memory system like the one in rust. So do that then.
- shultays 11y agorun time checks are run time checks, they add overhead. (imho) dangling pointers not worth the crippling the language like rust does.
- pcwalton 11y agoI've written hundreds of thousands of lines of working code in the "crippled" language you're referring to. And dangling pointers result in use-after-free, which frequently results in remote code execution vulnerabilities. Do you have a practical alternative to eliminating those RCE vulnerabilities, or should we accept them? To be clear, your position is an intellectually coherent one to take. But we should be clear about its implications.
- mhogomchungu 11y agoA pointer of type "void star" can be assigned to a pointer of any type and hence those casts are not necessary. Having them doesnt hurt,but they add clutter and shows lack of sufficient understanding of properties of pointers of type "void star". First argument to realloc takes a pointer of type "void star" and you passed in a pointer of type "int star" without casting it and this suggests you did the casts out of habit and i think its time to break the habit :-) ps: had to write "void star" because the "star" character was not showing up for some reason.
- userbinator 11y agoshows lack of sufficient understanding of properties of pointers ...or shows someone more familiar with C++ than C. Implicit casts between pointer-to-void and other pointer types are not allowed in C++.