Skip to content

Instantly share code, notes, and snippets.

@kjcolley7
Last active November 17, 2015 05:22
Show Gist options
  • Save kjcolley7/58b9e57210e6a1f31a92 to your computer and use it in GitHub Desktop.
Save kjcolley7/58b9e57210e6a1f31a92 to your computer and use it in GitHub Desktop.
Safer way to free an allocation in C

There are two headers in this gist which both define the destroy() macro with the same behavior but in slightly different ways.

##destroy.h##

This version of the destroy() macro works with any compiler that supports __typeof__, which includes gcc and clang but unfortunately not MSVC. This version is completely type safe, because no casts are used and therefore the compiler can check that all types are convertible.

##destroy_msvc.h##

This version of the destroy() macro works on all major compilers including gcc, clang, and MSVC. It is typesafe despite using casts because of the ErrorIfNotAtLeastDoublePointer() macro. This is a hacky workaround for the lack of __typeof__ in MSVC but the result is the same as the previous version. This version is therefore more portable but is not as clean of a solution as the first.

Both versions are used in the same way and have the same result.

/* Create an array of 20 ints */
int* myArr = malloc(20 * sizeof(*myArr));

...

/* Free myArr and set it to NULL */
destroy(&myArr);
#include <stdlib.h>
/*! Frees the pointer pointed to by the parameter and then sets it to NULL.
This is a safer alternative to calling free() directly, and is no more difficult to use.
Instead of calling free(myVar), just call destroy(&myVar). This will call free() on myVar
and then set myVar to NULL in a type safe and optimization safe manner. As with free(),
destroy(NULL) is safe and is a no-op. It's basically the C version of the following C++ code:
@code
template <typename T>
void destroy(T** pptr) {
if(!pptr) {
return;
}
free((void*)*pptr);
*pptr = nullptr;
}
@endcode
@note This macro does not cause double evaluation of pptr (which is a good thing)
*/
#define destroy(pptr) do { \
__typeof__(*(pptr)) volatile* _pptr = (pptr); \
if(!_pptr) { \
break; \
} \
free(*_pptr); \
*_pptr = NULL; \
} while(0)
#include <stdlib.h>
/*! Causes a compiler error if pptr isn't at least a pointer to a pointer (to anything)
@note This macro doesn't cause pptr to be evaluated at all, so it has no side effects
*/
#define ErrorIfNotAtLeastDoublePointer(pptr) sizeof(&**(pptr))
/*! Frees the pointer pointed to by the parameter and then sets it to NULL.
This is a safer alternative to calling free() directly, and is no more difficult to use.
Instead of calling free(myVar), just call destroy(&myVar). This will call free() on myVar
and then set myVar to NULL in a type safe and optimization safe manner. As with free(),
destroy(NULL) is safe and is a no-op. It's basically the C version of the following C++ code:
@code
template <typename T>
void destroy(T** pptr) {
if(!pptr) {
return;
}
free((void*)*pptr);
*pptr = nullptr;
}
@endcode
@note This macro does not cause double evaluation of pptr (which is a good thing)
*/
#define destroy(pptr) (ErrorIfNotAtLeastDoublePointer(pptr), _destroy((void* volatile*)(pptr)))
static inline void _destroy(void* volatile* pptr) {
if(!pptr) {
return;
}
free(*pptr);
*pptr = NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment