2014-12-21 8 views
5

che uso realloc ridimensionare la memoria allocata:matrici dinamiche: utilizzando realloc() senza perdite di memoria

char **get_channel_name(void) 
{ 
    char **result; 
    int n; 

    result = (char **) 0; 
    for (elem = snd_mixer_first_elem(handle), n = 0; elem; elem = snd_mixer_elem_next(elem)) { 
     if (!snd_mixer_selem_is_active(elem)) 
      continue; 
     if (snd_mixer_selem_has_playback_volume(elem) && 
      snd_mixer_selem_has_playback_switch(elem) && 
      snd_mixer_selem_has_capture_switch(elem)) { 
      if (result == (char **) 0) 
       result = (char **) malloc(sizeof(char *)); 
      else 
       result = (char **) realloc(result, sizeof(char *) * (n + 1)); /* nulled but not freed upon failure */ 
      result[n++] = strdup(snd_mixer_selem_get_name(elem)); 
     } 
    } 

    if (result == (char **) 0) 
     return NULL; 

    result = (char **) realloc(result, sizeof(char *) * (n + 1)); /* nulled but not freed upon failure */ 
    result[n] = NULL; 

    return result; 
} 

Quando controllo codice con utensile cppcheck statico C/C analisi del codice ++, stampate le seguenti Warings:

Common realloc mistake: 'result' nulled but not freed upon failure 

Come posso risolvere queste 2 possibili perdite di memoria?

risposta

9

Se realloc() fallisce restituisce NULL.

Quindi, se si fa (e supponendo realloc() potrebbe fallire)

result = realloc(result, ...); 

result saranno assegnati NULL e ciò che essa ha di non è free() Ed e l'indirizzo di essere free() ed è perduto.

Per correggere questo do:

void * tmp = realloc(result, ...); 
if (NULL == tmp) 
{ 
    /* Handle error case, propably freeing what result is pointing to. */ 
} 
else 
{ 
    result = tmp; 
} 
3

Il trucco per fissare l'errore "annullato, ma non liberato in caso di errore" è quello di memorizzare il valore restituito da realloc in un puntatore a parte, e controllare che non NULL prima di riassegnazione il vecchio puntatore:

char **tmp = (char **) realloc(result, sizeof(char *) * (n + 1)); 
if (tmp) { 
    result = tmp; 
} else { 
    ... // Handle reallocation error 
} 

Ora che l'assegnazione di result è protetta da NULL assegno, avete il vecchio valore di lavorare con: si potrebbe free se si vuole, oppure potresti continuare a usarlo se necessario. Il codice originale, d'altra parte, non ti dà la stessa opzione.

Nota: Quando si passa NULL puntatore ad realloc, si comporta come malloc. Ecco perché si può cadere la condizionale nel primo utilizzo di realloc - sostituire questo

if (result == (char **) 0) 
    result = (char **) malloc(sizeof(char *)); 
else 
    result = (char **) realloc(result, sizeof(char *) * (n + 1)); 

con questo:

char** tmep = (char **) realloc(result, sizeof(char *) * (n + 1)); 
... // check temp and assign result here 

Non dimenticare di impostare n a zero - attualmente, è utilizzato inizializzato, che è un comportamento indefinito.