Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to free previously allocated memory when errors occured?

Given a function declaration like this:

int base_address(zval *object, int add_prefix, char **base_address TSRMLS_DC) {    
    int result;

    char *host;
    long port;
    char *prefix;  

    host = ... get host from object ...;
    port = ... get port from object ...;
    prefix = ... get prefix from object ...;

    result = SUCCESS;

    if (asprintf(base_address, "%s:%ld/%s", host, port, prefix) < 0) {
        result = FAILURE;
    }

    return result;
}

void my_func() {
    char *base_address;
    char *ping_url;

    if (base_address(getThis(), 0, &base_address TSRMLS_CC) == FAILURE) {
        MALLOC_ERROR();
    }

    if (asprintf(&ping_url, "%s/ping", base_address) < 0) {
        MALLOC_ERROR();
    }

   ... do some stuff with base address ...

    // release both, as everything worked
    free(base_address);
    free(ping_url);
}

If the first call to base_address succeeded and the second call to asprintf() failed, how do I cleanly skip to the end of the function in order to safely release allocated memory?

Is there some standard pattern how to avoid memory leaks in these situations where memory is allocated one after another (and each allocation might fail) without too much code duplication or goto statements?

like image 327
Max Avatar asked Sep 20 '11 20:09

Max


People also ask

What happens if you free already freed memory?

If you attempt to read or write to memory that was previously freed, the result will be a conflict and the program will generate a memory error. For example, if a program calls the free() function for a particular block and then continues to use that block, it will create a reuse problem when a malloc() call is made.

What is freed memory?

Marks the chunk of memory previously used by the object as free. If possible, informs the operating system that a chunk of memory is free for other programs to use.

What happens to freed memory in C?

free() just declares, to the language implementation or operating system, that the memory is no longer required. When it is written over is not defined behavior.

How do you avoid double free in C++?

Double Free A simple technique to avoid this type of vulnerability is to always assign NULL to a pointer after it has been freed. Subsequent attempts to free a null pointer will be ignored by most heap managers.


2 Answers

Don't be afraid of goto. It's the simplest, cleanest, and most legible way of handling exceptions in C:

  • You don't repeat yourself. Duplicated code is error-prone.

  • You don't create deeply nested code. Deep nesting is illegible.

  • You don't hide behind do {...} while (0) and break. Good code says what it means.

Here's a basic example:

int operation() {

    int result = SUCCESS;

    if ((result = may_fail_first()) == FAILURE) {
        goto failed_first;
    }

    if ((result = may_fail_second()) == FAILURE) {
        goto failed_second;
    }

    // If your cleanup code doesn't ordinarily need to run.
    goto end;

failed_second:
    cleanup_second();

    // If you don't need to clean up everything.
    goto end;

failed_first:
    cleanup_first();

end:
    return result;

}
like image 176
Jon Purdy Avatar answered Sep 28 '22 07:09

Jon Purdy


This is one of the sane usages of goto for error handling:

if (base_address(getThis(), 0, &base_address TSRMLS_CC) == FAILURE) {
    goto end;
}

if (asprintf(&ping_url, "%s/ping", base_address) < 0) {
    goto release_address;
}

// do stuff

release_address:
free(base_address);
end:

This way you don't have to repeat the same releasing code in case you have many allocating calls which depend on each other.

You may want to refer to another of my answers here, which talks about the general case.

like image 30
Blagovest Buyukliev Avatar answered Sep 28 '22 08:09

Blagovest Buyukliev