This is why it's considered bad form to cast the result of malloc in C. Of course, modern compilers will warn about implicit prototypes, and as of C99 it's no longer legal.
This is why it's considered bad form to cast the result of malloc in C. Of course, modern compilers will warn about implicit prototypes, and as of C99 it's no longer legal.
https://nickdesaulniers.github.io/blog/2016/05/30/data-model...
test.c:10:12: warning: implicitly declaring library function 'malloc' with type 'void *(unsigned long)'
[-Wimplicit-function-declaration]
I think that having a prototype mismatch with the actual declared function is undefined behavior, so this is a legal way to resolve it, but not every compiler will. Older compilers tended to treat malloc as just another function and wouldn't do this.I was able to replicate the older behavior by wrapping malloc in my own function. In one file:
int main()
{
int* p;
p = (int*)wrapped_malloc(sizeof(int));
*p = 10;
return 0;
}
And in another file: void *wrapped_malloc(int size) {
return malloc(size);
}
Compiling them into one program results in a crash. The relevant bit of assembly is: 0000000100000f4f movslq %eax, %rdi
So it is indeed only extracting the lower 32 bits of the returned pointer.The page looks pretty old (the IA-64 reference sure is dated, anyway) so I'd guess that it was referring to an older compiler that didn't have a special case for malloc like this.
int main()
{
int* p;
p = (int*)wrapped_malloc(sizeof(int));
*p = 10;
return 0;
}
void *wrapped_malloc(int size) {
return malloc(size);
}
And the actual error: test.c:9:11: error: conflicting types for 'wrapped_malloc'
void *wrapped_malloc(int size) {
^
test.c:4:19: note: previous implicit declaration is here
p = (int*)wrapped_malloc(sizeof(int));
Are you doing anything differently?If you call malloc without a prototype in scope, bad things can happen. Just because it happens to work out OK with the platform and compiler that you tested doesn't mean that it will work everywhere or that it will keep working in the future.
mov ecx, 1000
call malloc
cdqe
mov QWORD PTR p$[rsp], rax
I'll have to check if it's still true today, but Windows/the VC++ CRT certainly used not have no qualms about handing out pointers to memory below the 4GByte mark. So if you have a problem like this, it can go undetected for quite some time...(Don't know about Linux. 64-bit OS X binaries usually start with a 4GByte section at 0, so the bottom 4GBytes simply isn't available.)