Linke
Linke

Reputation: 358

Is it safe to use void** in special cases? Still undefined behavior?

I want to create a function that frees the memory pointed to by the pointer and assigns this pointer to NULL. So I have to declare the argument as void** (an indirect pointer), I know that void* is safe for converting pointers, and using void** is undefined behavior. But I think that should be no problem in this situation.Will this function safely free any memory allocated by malloc() without undefined behavior? Ask the hackers to help or suggest a better way.

C code:

#include <stdio.h>
#include <stdlib.h>

// If I use safeFree(&mac_arr); ,
// it will warn "Incompatible pointer types passing ' int **' to parameter of type ' void **'"
// So I used #define, don't care about this.

#define SAFE_FREE(p) safeFree((void **)&(p))

void safeFree(void ** ptr);

int main(void) {
    int *mac_arr = malloc(sizeof *mac_arr);
    SAFE_FREE(mac_arr);
    return 0;
}

void safeFree(void ** ptr){
    if (ptr != NULL && *ptr != NULL) {
        free(*ptr);
        *ptr = NULL;
    }
}

Upvotes: 0

Views: 291

Answers (2)

Ian Abbott
Ian Abbott

Reputation: 17413

The pointer types int ** and void ** are incompatible. The type cast just masks the incompatibility.

You could define:

#define SAFE_FREE(p) ((void)(free(p), (p) = NULL))

Upvotes: 4

Eric Postpischil
Eric Postpischil

Reputation: 222941

The behavior of such code is not defined by the C standard.

In main, mac_arr is an int *. The parameter safeFree receives is a pointer to void *. But int * and void * are not compatible types as defined by the C standard. They may have different sizes, alignment requirements, and representations. So converting the address of mac_arr from int ** to void ** and using *ptr for an lvalue of type void * is not portable.

It might “work” in many C implementations.

The SAFE_FREE macro you are contemplating is not a great remedy for pointer problems. While it sets the current pointer to an object to null, it has no way of affecting other pointers to the same object, such as links in linked lists or links in other data structures.

(It also does not need to test *ptr != NULL. free is specified to do nothing when it is passed a null pointer, so you would just be doubling up on a test that is already performed.)

Upvotes: 6

Related Questions