Perché ottengo un errore di asserzione C malloc?


86

Sto implementando un algoritmo polinomiale divide et impera in modo da poterlo confrontare con un'implementazione OpenCL, ma non riesco a mettermi mallocal lavoro. Quando eseguo il programma, alloca un sacco di cose, controlla alcune cose, quindi invia size/2l'algoritmo. Quindi quando colpisco di mallocnuovo la linea sputa questo:

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted

La linea in questione è:

Ho controllato la dimensione con una fprintf, ed è un numero intero positivo (di solito 50 a quel punto). Ho provato a chiamare anche malloccon un numero semplice e continuo a ricevere l'errore. Sono solo perplesso su quello che sta succedendo e nulla di Google che ho trovato finora è utile.

Qualche idea su cosa sta succedendo? Sto cercando di capire come compilare un GCC più recente nel caso si tratti di un errore del compilatore, ma ne dubito davvero.


sospetto che il problema sia in realtà una riga prima di quella. Forse una doppia libera?
Mitch Wheat

3a riga nel programma: int * mult (int size, int * a, int * b) {int * out, i, j, * tmp1, * tmp2, * tmp3, * tmpa1, * tmpa2, * tmpb1, * tmpb2 , d, * res1, * res2; fprintf (stdout, "size:% d \ n", size); out = (int *) malloc (sizeof (int) * size * 2);
Chris,

Risposte:


100

99,9% di probabilità che tu abbia danneggiato la memoria (over- o underflow di un buffer, scritto su un puntatore dopo che è stato liberato, chiamato free due volte sullo stesso puntatore, ecc.)

Esegui il tuo codice sotto Valgrind per vedere dove il tuo programma ha fatto qualcosa di sbagliato.


1
fisso. Valgrind ha sicuramente aiutato. Ho trascritto il mio vecchio codice matlab in modo errato e avevo un ciclo for che iterava su j, quindi all'interno ha fatto j ++ che ha sovrascritto la maggior parte dell'array su cui stava scrivendo e in qualche modo ha causato il fallimento di malloc. grazie per l'aiuto!
Chris

Valgrind era solo lo strumento di cui avevo bisogno per capire cosa stava succedendo quando ho ricevuto questo errore. Grazie per averlo menzionato.
alexwells

78

Per darti una migliore comprensione del motivo per cui questo accade, vorrei espandere un po 'la risposta di @ r-samuel-klatchko.

Quando chiami malloc, ciò che sta realmente accadendo è un po 'più complicato che darti solo un pezzo di memoria con cui giocare. Sotto il cofano, mallocmantiene anche alcune informazioni di pulizia sulla memoria che ti ha dato (soprattutto, le sue dimensioni), in modo che quando chiami free, sappia cose come quanta memoria liberare. Queste informazioni vengono generalmente conservate subito prima che la posizione di memoria ti venga restituita da malloc. Informazioni più esaurienti possono essere trovate su Internet ™ , ma l'idea (molto) di base è qualcosa del genere:

Basandosi su questo (e semplificando notevolmente le cose), quando si chiama malloc, è necessario ottenere un puntatore alla parte successiva della memoria disponibile. Un modo molto semplice per farlo è guardare il bit di memoria precedente che ha ceduto e spostare i sizebyte più in basso (o in alto) nella memoria. Con questa implementazione, si finisce con la memoria cercando qualcosa di simile dopo l'attribuzione p1, p2e p3:

Allora, qual è la causa del tuo errore?

Bene, immagina che il tuo codice scriva erroneamente oltre la quantità di memoria che hai allocato (o perché hai allocato meno del necessario come era il tuo problema o perché stai usando le condizioni al contorno sbagliate da qualche parte nel tuo codice). Supponiamo che il tuo codice scriva così tanti dati inp2 che inizia sovrascrivere ciò che è in p3's sizecampo. Alla successiva chiamata malloc, esaminerà l'ultima posizione di memoria restituita, il campo delle dimensioni, si sposterà p3 + sizee inizierà ad allocare memoria da lì. Poiché il codice è stato sovrascritto size, tuttavia, questa posizione di memoria non è più dopo la memoria allocata in precedenza.

Inutile dire che questo può rovinare il caos! Gli implementatori di mallochanno quindi inserito una serie di "asserzioni", o controlli, che cercano di fare un po 'di controlli di integrità per rilevare questo (e altri problemi) se stanno per accadere. Nel tuo caso particolare, queste affermazioni vengono violate e quindi si mallocinterrompono, dicendoti che il tuo codice stava per fare qualcosa che in realtà non dovrebbe fare.

Come affermato in precedenza, si tratta di una grossolana semplificazione, ma è sufficiente per illustrare il punto. L'implementazione glibc di mallocè più di 5k righe e ci sono state notevoli quantità di ricerca su come costruire buoni meccanismi di allocazione dinamica della memoria, quindi non è possibile coprire tutto in una risposta SO. Si spera che questo ti abbia dato un'idea di cosa sta realmente causando il problema!


17

La mia soluzione alternativa all'utilizzo di Valgrind:

Sono molto felice perché ho appena aiutato il mio amico a eseguire il debug di un programma. Il suo programma ha avuto questo problema esatto ( malloc()causando l'interruzione), con lo stesso messaggio di errore da GDB.

Ho compilato il suo programma utilizzando Address Sanitizer con

E poi è corso gdb new. Quando il programma viene terminato per SIGABRTcausa in un successivo malloc(), vengono stampate molte informazioni utili:

Diamo un'occhiata all'output, in particolare alla traccia dello stack:

La prima parte dice che c'è un'operazione di scrittura non valida in new.c:59. Quella riga si legge

La seconda parte dice che il ricordo su cui è avvenuta la cattiva scrittura viene creato new.c:55. Quella riga si legge

Questo è tutto. Mi ci è voluto solo meno di mezzo minuto per individuare il bug che ha confuso il mio amico per alcune ore. È riuscito a localizzare il fallimento, ma è un successivomalloc() chiamata che non è riuscita, senza essere in grado di individuare questo errore nel codice precedente.

Riassumendo: prova il -fsanitize=addressGCC o Clang. Può essere molto utile durante il debug di problemi di memoria.


1
Mi hai appena salvato la vita.
Nate Symer


2

Ho ricevuto il seguente messaggio, simile al tuo:

    programma: malloc.c: 2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) & ((av) -> bins [((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size)> = (unsigned long) ((((__ builtin_offsetof (struct malloc_chunk, fd_nextsize)) + ((2 * (sizeof (size_t))) - 1)) & ~ ((2 * (sizeof (size_t))) - 1))) && ((old_top) -> size & 0x1) && ((unsigned long) old_end & pagemask) == 0) 'non riuscita.

Prima di utilizzare malloc è stato commesso un errore in una chiamata al metodo. Ha sovrascritto erroneamente il segno di moltiplicazione "*" con un "+", durante l'aggiornamento del fattore dopo l'operatore sizeof () - quando si aggiunge un campo a un array di caratteri non firmato.

Ecco il codice responsabile dell'errore nel mio caso:

    UCHAR * b = (UCHAR *) malloc (sizeof (UCHAR) +5);
    b [INTBITS] = (alcuni calcoli);
    b [BUFSPC] = (alcuni calcoli);
    b [BUFOVR] = (alcuni calcoli);
    b [BUFMEM] = (alcuni calcoli);
    b [MATCHBITS] = (alcuni calcoli);

In un altro metodo più tardi, ho usato di nuovo malloc e ha prodotto il messaggio di errore mostrato sopra. La chiamata era (abbastanza semplice):

    UCHAR * b = (UCHAR *) malloc (sizeof (UCHAR) * 50);

Pensa di usare il segno '+' - alla prima chiamata, che ha portato a errori di calcolo in combinazione con l'inizializzazione immediata dell'array dopo (sovrascrivere la memoria che non era allocata all'array), ha portato un po 'di confusione nella mappa di memoria di malloc. Pertanto la seconda chiamata è andata storta.


0

Abbiamo ricevuto questo errore perché ci siamo dimenticati di moltiplicare per sizeof (int). Nota che l'argomento di malloc (..) è un numero di byte, non un numero di parole macchina o altro.


0

ho avuto lo stesso problema, ho usato malloc su n di nuovo in un ciclo per aggiungere nuovi dati char * string. ho affrontato lo stesso problema, ma dopo aver rilasciato il void free()problema di memoria allocata sono stati risolti


-2

Stavo portando un'applicazione da Visual C a gcc su Linux e ho avuto lo stesso problema con

malloc.c: 3096: sYSMALLOc: asserzione utilizzando gcc su UBUNTU 11.

Ho spostato lo stesso codice in una distribuzione Suse (su un altro computer) e non ho alcun problema.

Ho il sospetto che i problemi non siano nei nostri programmi ma nella propria libc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.