I want to know if it is ok to free() a pointer cast to another type.
For instance if I do this:
char *p = malloc (sizeof (int));
int *q = (int *)p;
free (q);
I get no warning on gcc (-Wall).
On linux, the man pages on free says it is illegal to call free on a pointer that was not returned by malloc(), calloc() or realloc(). But what happens if the pointer was cast to another type in between?
I ask this because I read that the C standard does not require different pointer types (e.g. int* and char*) to have the same size, and I fail to understand how this is possible since they both need to be convertible to a void* in order to call the malloc/free functions.
Is the above code legal?
It’s probably safe, but it’s not absolutely guaranteed to be safe.
On most modern systems, all pointers (at least all object pointers) have the same representation, and converting from one pointer type to another just reinterprets the bits that make up the representation. But the C standard doesn’t guarantee this.
This gives you a
char*pointer tosizeof (int)bytes of data (assumingmalloc()succeeds.)This converts the
char*pointer to anint*pointer. Sinceintis bigger thanchar, anint*pointer could require less information to indicate what it points to. For example, on a word-oriented machine, anint*might point just point to a word, while achar*has to contain a word pointer and an offset that indicates which byte within the word it points to. (I’ve actually worked on a system, the Cray T90, that worked like this.) So a conversion fromchar*toint*can actually lose information.Since
free()takes an argument of typevoid*, the argumentqis implicitly converted fromint*tovoid*. There is no guarantee in the language standard that converting achar*pointer toint*, and then converting the result tovoid*, gives you the same result as converting achar*directly to avoid*.On the other hand, since
malloc()always returns a pointer that’s correctly aligned to point to any type, even on a system whereint*andchar*have different representations, it’s unlikely to cause problems in this particular case.So your code is practically certain to work correctly on any system you’re likely to be using, and very very likely to work correctly even on exotic systems you’ve probably never seen.
Still, I advise writing code that you can easily demonstrate is correct, by saving the original pointer value (of type
char*) and passing it tofree(). If it takes several paragraphs of text to demonstrate that your code is almost certainly safe, simplifying your assumptions is likely to save you effort in the long run. If something else goes wrong in your program (trust me, something will), it’s good to have one less possible source of error to worry about.A bigger potential problem with your code is that you don’t check whether
malloc()succeeded. You don’t do anything that would fail if it doesn’t (both the conversion and thefree()call are ok with null pointers), but if you refer to the memory you allocated you could be in trouble.UPDATE:
You asked whether your code is legal; you didn’t ask whether it’s the best way to do what you’re doing.
malloc()returns avoid*result, which can be implicitly converted to any pointer-to-object type by an assignment.free()takes avoid*argument; any pointer-to-object type argument that you pass to it will be implicitly converted tovoid*. This round-trip conversion (void*tosomething_else*tovoid*) is safe. Unless you’re doing some kind of type-punning (interpreting the same chunk of data as two different types), there’s no need for any casts.Rather than:
you can just write:
Note the use of
sizeof *pin the argument tomalloc(). This gives you the size of whateverppoints to without having to refer to its type explicitly. It avoids the problem of accidentally using the wrong type:which the compiler likely won’t warn you about.