How to free previously allocated memory when errors occur?

Given the function declaration, as follows:

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 succeeds and the second call to asprintf () fails, how can I go to the end of the function to safely free the allocated memory?

Is there any standard template for avoiding memory leaks in situations where memory is allocated one after another (and each allocation may fail) without excessive duplication of code or goto statements?

+5
source share
4 answers

NULL , free , malloc ed ( ). (, , -1, fd).

goto () - "" . , goto , -, , , , "gotos around gotos" . NULL ( ).

.


:

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

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

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

    // stuff... and assign return value (or return directly) if applicable,
    // assign NULL to variables which contain values that should
    // not be free'd, etc (use as guards!).
    // I prefer to add guards into the cleanup vs. "skip over it".
    // I vary rarely, if ever, have multiple cleanup sections -- in most
    // cases this would indicate the need for additional function(s) to me.

  cleanup:
    free(base_address);
    if (ping_url) {
       // perhaps need additional cleanup        
       free(ping_url);
    }

    // Return value, if applicable. (If a "direct return" above isn't
    // advisable for the given function due to cleanup rules.)
}
+2

goto. , C:

  • . .

  • . .

  • do {...} while (0) break. , .

:

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;

}
+9

goto :

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:

, , , .

here, .

+7

c, , ()

if ( base_address( ... ) )
{
  if (asprint( ... ))
  {
     /// do some stuff 

     free(ping_url);
  }
  free( base_address);
}
+2
source

All Articles