2010-03-19 15 views
9

Sono un principiante in C. Durante la lettura del codice sorgente di git, ho trovato questa funzione wrapper attorno a malloc.Involucro malloc - C

void *xmalloc(size_t size) 
{ 
    void *ret = malloc(size); 
    if (!ret && !size) 
     ret = malloc(1); 
    if (!ret) { 
     release_pack_memory(size, -1); 
     ret = malloc(size); 
     if (!ret && !size) 
      ret = malloc(1); 
     if (!ret) 
      die("Out of memory, malloc failed"); 
    } 
#ifdef XMALLOC_POISON 
    memset(ret, 0xA5, size); 
#endif 
    return ret; 
} 

Domande

  1. non riuscivo a capire perché stanno usando malloc(1)?
  2. Cosa fa release_pack_memory e non riesco a trovare questa implementazione di funzioni nell'intero codice sorgente.
  3. Cosa fa il #ifdef XMALLOC_POISON memset(ret, 0xA5, size);?

Sto progettando di riutilizzare questa funzione sul mio progetto. Si tratta di un buon wrapper intorno a malloc?

Qualsiasi aiuto sarebbe fantastico.

+7

Complimenti per la lettura del codice di programmi complessi già esistenti - Vorrei che più sviluppatori hanno fatto questo. – Lars

+3

Per la domanda 2: La sua definizione è in sha1_file.c (è compito della memoria fare con gli oggetti del pacchetto git, presumibilmente) e il suo prototipo è in git-compat-util.h. (Suggerimento: se stai cercando il codice sorgente di git, usa 'git grep release_pack_memory' per trovarlo!) – Cascabel

+1

@Lars: Grazie. @Jefromi: buon punto su 'git grep'. –

risposta

3
  1. malloc (0) non funziona su tutte le piattaforme, nel qual caso viene effettuata un'assegnazione di un byte. Consentendo l'assegnazione di blocchi di memoria di lunghezza 0 semplifica la logica di livello superiore del programma.

  2. Non so.

  3. Riempiendo la memoria allocata con un valore diverso da zero, è più semplice trovare errori nel programma in cui viene utilizzata la memoria senza un'inizializzazione corretta: il programma si arresta quasi immediatamente in questi casi. Poiché il riempimento della memoria richiede tempo, viene definito da un preprocessore, quindi viene compilato solo quando lo si desidera.

+1

Il comportamento di 'malloc (0)' è definito dall'implementazione. Restituisce o un puntatore NULL o un puntatore non nullo a zero byte di dati (che, ovviamente, non è mai possibile annullare la chiamata). C99 §7.20.3 Funzioni di gestione della memoria: "Se la dimensione dello spazio richiesto è zero, il comportamento è definito dall'implementazione: viene restituito un puntatore nullo oppure il comportamento è come se la dimensione fosse un valore diverso da zero , tranne che il puntatore restituito non deve essere utilizzato per accedere a un oggetto. " –

2

Per la domanda 1:

La norma non definisce il comportamento di malloc(0). Questo potrebbe restituire un puntatore valido o potrebbe restituire NULL. Diverse implementazioni gestiscono diversamente in modo che il codice ricada su malloc(1) per ottenere un comportamento coerente.

Per la domanda 3:

imposta il contenuto del buffer a qualcosa di 'strano'. In questo modo, si spera che il tuo codice non contenga che il contenuto sia qualcosa di specifico (che malloc non garantisce).

+0

Ti consiglia di utilizzare questo wrapper? –

+0

@Appu - cambiando da 0 a 1 e facendo il memset va bene. Il dado sulla politica di OOM dipende da ciò che stai scrivendo. La politica va bene per un'utilità della riga di comando che fa una cosa ed esce. Il criterio può o non può andare bene per un server di lunga durata (vuoi uscire dal processo o vuoi pulire la richiesta corrente e riprovare). La politica non è accettabile per una libreria generica poiché la politica su OOM dovrebbe essere decisa dall'applicazione principale. –

+0

Buon punto. Il codice che scriverò è per una biblioteca. Quindi penso che dovrei evitare 'morire'. –

1

non ho familiarità con questo wrapper, ma qui è quello che il suo facendo

1 - se size = 0 è stato specificato allora assegna 1 byte invece se il malloc sottostante non lo ha fatto

questo è presumibilmente fatto in modo che un chiamante può ancora fare gratis su di esso (come realloc)

2 presumo la sua per cercare di forzare il sottosistema di memoria sottostante per guardare più difficile per la memoria

3 le forze XMALLOC_POISON di buffer ad uno stato noto questa è una pratica comune al fine di prevenire e rilevare bug strani causati da dati non inizializzati

In secondo luogo - perché si desidera avvolgere malloc. Inizia con l'idea di cosa vuoi fare e poi implementalo o copia un'implementazione. Motivi per il confezionamento malloc

  1. rilevamento di perdite
  2. analisi di utilizzo
  3. memoria pool
  4. debug (come il XMALLOC_POISON)
  5. applicate controllo

Quasi tutti questi può essere fatto con valgrind - che fa molto di più.

'la scrittura di codice solido' libro ha una buona serie di involucri di memoria per 1,4 e 5

+0

Grazie per la risposta. Onestamente, sono un po 'perso nel mondo C. Quindi per evitare di fare errori, sto leggendo il codice di altri programmi e scoprendo come scrivono il codice. –

+2

"questo è presumibilmente fatto in modo che un chiamante possa ancora liberare su di esso" - è ancora possibile chiamare gratuitamente o realloc su un puntatore nullo. Non conosco la fonte di Git, ma più probabilmente è fatto per garantire che un ritorno 0 possa essere trattato in modo definitivo dal chiamante come un errore, anche se l'input era 0. O possibilmente per assicurare che i puntatori a diversi 0- le allocazioni dimensionate sono comparabili ("questo non è il tuo buffer di dimensioni zero, quindi non deve essere la tua valigia!"). –