2014-12-21 21 views
5

używam realloc do rozmiaru pamięci przydzielonej:Dynamiczne tablice: za pomocą realloc() bez pamięci przecieki

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

Kiedy kod z narzędziem cppcheck statyczna C/C analizy kodu ++ sprawdzić, drukowane następujące warings:

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

Jak mogę naprawić te 2 możliwe wycieki pamięci?

Odpowiedz

9

Jeśli nie powiedzie się realloc(), zwróci NULL.

Więc jeśli nie (i zakładając realloc() zawiedzie)

result = realloc(result, ...); 

result zostanie przypisany NULL i co wskazał nie jest free() ed i adres będzie free() ed jest stracone.

Aby rozwiązać to zrobić:

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

Trick do naprawienia błędu „nulled ale nie uwolniony po awarii” jest do przechowywania wartości zwróconej przez realloc do oddzielnego wskaźnika, i sprawdź, czy nie NULL przed realokacja stary wskaźnik:

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

teraz przypisanie result jest chroniona NULL czeku, masz starą wartość do pracy z: można free, jeśli chcesz, lub możesz kontynuować korzystanie z niego, jeśli zajdzie taka potrzeba. Z drugiej strony oryginalny kod nie daje tej samej opcji.

Uwaga: Po przejechaniu NULL wskaźnik realloc, zachowuje się jak malloc. Dlatego można upuścić warunkowego w pierwszym użyciem realloc - zastąpić ten

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

z tym:

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

Nie zapomnij ustawić n do zera - obecnie jest on wykorzystywany niezainicjowany, który jest niezdefiniowanym zachowaniem.