2014-12-21 11 views
5

I realloc verwenden den Speicher, um die Größe zugeordnet:Dynamische Arrays: using realloc() ohne Speicherlecks

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; 
} 

Wenn ich Code überprüfen mit cppcheck Werkzeug statische C/C++ Code-Analyse, die folgenden Warings gedruckt:

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

Wie kann ich das beheben diese 2 möglich Speicherlecks?

Antwort

9

Wenn realloc() ausfällt kehrt NULL.

Also, wenn Sie zu tun (und realloc() scheitern würde unter der Annahme)

result = realloc(result, ...); 

result wird NULL zugewiesen werden und was es zeigte auf nicht free() ed und die Adresse sein free() ed verloren.

dies tun zu beheben:

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

Der Trick, um den „auf Null gesetzt, aber nicht bei einem Ausfall befreit“ auf dem Festsetzung Fehler ist, den Wert von realloc in einen separaten Zeiger zurückgegeben zu speichern, und überprüfen Sie es für NULL vor Neuzuweisung der alte Zeiger:

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

Nun, da die Zuordnung von result durch NULL Check geschützt ist, müssen Sie den alten Wert mit zu arbeiten: Sie könnte es free wenn Sie wollen, oder Sie könnten es weiterhin verwenden, wenn Sie müssen. Der ursprüngliche Code, auf der anderen Seite, nicht gibt Ihnen die gleiche Option.

Hinweis: Wenn Sie NULL Zeiger auf realloc passieren, verhält es sich wie malloc. Deshalb sollten Sie die bedingte in der ersten Verwendung von realloc fallen kann - ersetzen Sie diese

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

mit diesem:

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

nicht n auf Null zu setzen Vergessen - zur Zeit, wird es verwendet, nicht initialisierte, die ist undefiniertes Verhalten.