I've tried to read up on the other questions here on SO with similar titles, but they are all a tiny bit too complex for me to be able to apply the solution (or even explanation) to my own issue, which seems to be of a simpler nature.
In my case, I have a wrapper around free()
which sets the pointer to NULL
after freeing it:
void myfree(void **ptr)
{
free(*ptr);
*ptr = NULL;
}
In the project I'm working on, it is called like this:
myfree((void **)&a);
This makes gcc
(4.2.1 on OpenBSD) emit the warning "dereferencing type-punned pointer will break strict-aliasing rules" if I crank up the optimization level to -O3
and add -Wall
(not otherwise).
Calling myfree()
the following way does not make the compiler emit that warning:
myfree((void *)&a);
And so I wonder if we ought to change the way we call myfree()
to this instead.
I believe that I'm invoking undefined behaviour with the first way of calling myfree()
, but I haven't been able to wrap my head around why. Also, on all compilers that I have access to (clang
and gcc
), on all systems (OpenBSD, Mac OS X and Linux), this is the only compiler and system that actually gives me that warning (and I know emitting warnings is a nice optional).
Printing the value of the pointer before, inside and after the call to myfree()
, with both ways of calling it, gives me identical results (but that may not mean anything if it's undefined behaviour):
#include <stdio.h>
#include <stdlib.h>
void myfree(void **ptr)
{
printf("(in myfree) ptr = %p\n", *ptr);
free(*ptr);
*ptr = NULL;
}
int main(void)
{
int *a, *b;
a = malloc(100 * sizeof *a);
b = malloc(100 * sizeof *b);
printf("(before myfree) a = %p\n", (void *)a);
printf("(before myfree) b = %p\n", (void *)b);
myfree((void **)&a); /* line 21 */
myfree((void *)&b);
printf("(after myfree) a = %p\n", (void *)a);
printf("(after myfree) b = %p\n", (void *)b);
return EXIT_SUCCESS;
}
Compiling and running it:
$ cc -O3 -Wall free-test.c
free-test.c: In function 'main':
free-test.c:21: warning: dereferencing type-punned pointer will break strict-aliasing rules
$ ./a.out
(before myfree) a = 0x15f8fcf1d600
(before myfree) b = 0x15f876b27200
(in myfree) ptr = 0x15f8fcf1d600
(in myfree) ptr = 0x15f876b27200
(after myfree) a = 0x0
(after myfree) b = 0x0
I'd like to understand what is wrong with the first call to myfree()
and I'd like to know if the second call is correct. Thanks.
NULL
may hide accesses to freed memory. – Refundfree(NULL)
is harmless, dereferencingNULL
is not. Thus I believe the reasoning is (this is in a collaborative project that's been running for a number of years) it's better to be told about referencing freed memory than to catch a doublefree()
call. I've been thinking about using the Boehm GC for memory leak detection, and/or Valgrind, but haven't come around to do that just yet as I'm fairly new in the project. – Refund