Objections to free_if_heap(void *ptr)?

Viewed 52

I often would like to use a hypothetical free_if_heap(void *ptr) function, as this would let me return either malloc'd, static or stack objects without caring. e.g.

char *foo(int arg) {
    if (arg < 0) {
        return "arg is negative";
    }

    if (arg > 0) {
        size_t size = snprintf(NULL, 0, "%i is an invalid value", arg);
        char *ret = malloc(size + 1); // FIXME: handle failure
        sprintf(ret, "%i is an invalid value", arg);
        // I use a varargs macro for the three lines above, to avoid format string duplication errors.
    }

    return NULL;
}

void main(void) {
    for (int i = -1; i < 2; ++i) {
        char *err = foo(i);
        if (err) {
            printf("Error: %s\n", err);
            free_if_heap(err);
        }
    }
}

Obviously such a function must not be a good idea, as it has never even made it as far as malloc libraries, let alone the C standards.

Why is free_if_heap(void *ptr) a bad idea?


Update:

The function foo is just an example of a function which can return either a pointer to malloc'd data or to static/global data. It's not a serious function with a purpose.


Update:

Needing to know whether a pointer (of an otherwise known type, like char *, points to the heap is different from needing to know what type of data a void * pointer is pointing to.

free_if_heap(void *ptr) takes a void * argument to avoid having free_if_heap_char(char *ptr), free_if_heap_int(int *ptr) and a hundred others variants.

1 Answers

The function void free_if_heap(void *ptr) cannot be implemented portably* but it might be possible on selected targets, depending on the local implementation of malloc().

If you cannot or do not want to deal with allocated objects' life cycle, you should use a different programming language with a garbage collector. There are many efficient alternatives to C, such as Go. You could also try and use a conservative garbage collector for C such as the Boehm–Demers–Weiser garbage collector.

Note however that tracking memory allocated objects and properly disposing of them after use is not so difficult, but requires consistent conventions: for example your foo function should always return an allocated string or a null pointer:

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

char *foo(int arg) {
    if (arg < 0) {
        return strdup("arg is negative");
    }

    if (arg > 0) {
        size_t size = snprintf(NULL, 0, "%i is an invalid value", arg);
        char *ret = malloc(size + 1);
        if (ret != NULL) {
            snprintf(ret, size + 1, "%i is an invalid value", arg);
            return ret;
        }
    }
    return NULL;
}

int main(void) {
    for (int i = -1; i < 2; ++i) {
        char *err = foo(i);
        if (err) {
            printf("Error: %s\n", err);
            free(err);
        }
    }
    return 0;
}

(*) a portable implementation would be trivial and ineffective: void free_if_heap(void *ptr) {}

Related