Why you should NOT cast
June 16, 2007
People often write code like the following, and it's just
doomed to failure. Please do yourself a favor, run it, and never ever think
again about casting from a pointer to void * or vice-versa.
It throws warnings? Include the f!cking header.
The following two examples will make problems on architectures
where sizeof(int) != sizeof(void *), which includes AMD64,
sparc64, IA64 and perhaps many more.
Example 1
The following two files, main.c and
mmap_malloc.c need to remain separate. Compile with `gcc
-Wall -ansi -pedantic -o test1 main.c mmap_malloc.c` and watch what
happens. The value in x is truly invalid as far as memory regions
are concerned and would yield a segfault for sure.
#include <stdio.h>
int main(void)
{
char *x = (char *)mmap_malloc(10);
printf("%p\n", x);
return 0;
}
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
void *mmap_malloc(size_t n)
{
unsigned long long start;
void *ret;
int fd;
if ((fd = open("/dev/zero", O_RDWR)) < 0)
return NULL;
start = 0x123456;
start <<= 16;
ret = mmap((void *)start, n, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
close(fd);
printf("ret=%p\n", ret);
return ret;
}
Example 2
And here is one example — with the original malloc
even — that definitely segfaulted for me. Compile with `gcc
-Wall -fno-builtin-malloc -o test2 test2.c`. It is only visible in an
environment, where sizeof(char *) != sizeof(int), e.g.
x86_64, sparc64, and others. And you DO want to write portable
code.
#include <stdio.h>
int main(void)
{
unsigned int i;
for (i = 0; ; ++i) {
char *x = (char *)malloc(1048576); /* 1 MB */
printf("%p ... after %u iterations\n", x, i);
if(x == NULL)
break;
*x = '\0';
}
return 0;
}