Domanda

Ho un bug strano nel mio programma, mi sembra che malloc () stia causando un SIGSEGV, che per quanto riguarda la mia comprensione non ha alcun senso. Sto usando una libreria chiamata simclist per liste dinamiche.

Ecco una struttura a cui verrà fatto riferimento in seguito:

typedef struct {
    int msgid;
    int status;
    void* udata;
    list_t queue;
} msg_t;

Ed ecco il codice:

msg_t* msg = (msg_t*) malloc( sizeof( msg_t ) );

msg->msgid = msgid;
msg->status = MSG_STAT_NEW;
msg->udata = udata;
list_init( &msg->queue );

list_init è dove il programma fallisce, ecco il codice per list_init:

/* list initialization */
int list_init(list_t *restrict l) {
    if (l == NULL) return -1;

    srandom((unsigned long)time(NULL));

    l->numels = 0;

    /* head/tail sentinels and mid pointer */
    l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
    l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
    l->head_sentinel->next = l->tail_sentinel;
    l->tail_sentinel->prev = l->head_sentinel;
    l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
    l->head_sentinel->data = l->tail_sentinel->data = NULL;

    /* iteration attributes */
    l->iter_active = 0;
    l->iter_pos = 0;
    l->iter_curentry = NULL;

    /* free-list attributes */
    l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
    l->spareelsnum = 0;

#ifdef SIMCLIST_WITH_THREADS
    l->threadcount = 0;
#endif

    list_attributes_setdefaults(l);

    assert(list_repOk(l));
    assert(list_attrOk(l));

    return 0;
}

la riga l- > spareels = (struct list_entry_s **) malloc (SIMCLIST_MAX_SPARE_ELEMS * è dove SIGSEGV è causato secondo la traccia dello stack. Sto usando gdb / nemiver per il debugging ma sono in perdita. La prima volta che si chiama questa funzione funziona benissimo ma fallisce sempre la seconda volta. Come può malloc () causare un SIGSEGV?

Questa è la traccia dello stack:

#0  ?? () at :0
#1  malloc () at :0
#2  list_init (l=0x104f290) at src/simclist.c:205
#3  msg_new (msg_switch=0x1050dc0, msgid=8, udata=0x0) at src/msg_switch.c:218
#4  exread (sockfd=8, conn_info=0x104e0e0) at src/zimr-proxy/main.c:504
#5  zfd_select (tv_sec=0) at src/zfildes.c:124
#6  main (argc=3, argv=0x7fffcabe44f8) at src/zimr-proxy/main.c:210

Qualsiasi aiuto o approfondimento è molto apprezzato!

È stato utile?

Soluzione

malloc può segfault ad esempio quando l'heap è danneggiato. Verifica di non scrivere nulla oltre i limiti di qualsiasi allocazione precedente.

Altri suggerimenti

Probabilmente si verifica una violazione della memoria in un'altra parte del codice. Se sei su Linux, dovresti assolutamente provare valgrind. Non mi fiderei mai dei miei programmi C se non passa valgrind.

EDIT: un altro strumento utile è Recinzione elettrica . Glibc fornisce anche la MALLOC_CHECK_ per aiutare a risolvere i problemi di memoria. Questi due metodi non influiscono sulla velocità di corsa tanto quanto valgrind.

Probabilmente hai corrotto l'heap da qualche parte prima di questa chiamata da un buffer overflow o chiamando gratuito con un puntatore che non era allocato da malloc (o che era già liberato).

Se le strutture di dati interne utilizzate da malloc vengono corrotte in questo modo, malloc utilizza dati non validi e potrebbe bloccarsi.

Esistono una miriade di modi per attivare un dump principale da malloc () (e realloc () e calloc () ). Questi includono:

  • Overflow del buffer: scrittura oltre la fine dello spazio allocato (calpestando le informazioni di controllo che malloc () stava conservando lì).
  • Buffer underflow: scrivere prima dell'inizio dello spazio allocato (calpestando le informazioni di controllo che malloc () stava conservando lì).
  • Liberare memoria non allocata da malloc () . In un programma misto C e C ++, ciò includerebbe la liberazione della memoria allocata in C ++ da new .
  • Liberare un puntatore che punta a metà strada attraverso un blocco di memoria allocato da malloc () - che è un caso speciale del caso precedente.
  • Liberare un puntatore che era già stato liberato, il noto "doppio libero".

L'uso di una versione diagnostica di malloc () o l'abilitazione della diagnostica nella versione standard del tuo sistema, possono aiutare a identificare alcuni di questi problemi. Ad esempio, potrebbe essere in grado di rilevare piccoli underflow e overflow (poiché alloca spazio aggiuntivo per fornire una zona buffer attorno allo spazio richiesto) e probabilmente può rilevare tentativi di liberare memoria non allocata o già liberata o puntatori a metà dello spazio allocato, perché memorizzerà le informazioni separatamente dallo spazio allocato. Il costo è che la versione di debug occupa più spazio. Un allocatore davvero in grado sarà in grado di registrare la traccia dello stack e i numeri di riga per dirti dove si è verificata l'allocazione nel tuo codice o dove si è verificato il primo libero.

Dovresti provare a eseguire il debug di questo codice in isolamento, per vedere se il problema si trova effettivamente dove viene generato il segfault. (Sospetto che non lo sia).

Ciò significa:

# 1: compila il codice con -O0, per assicurarti che gdb ottenga le informazioni corrette sulla numerazione delle righe.

# 2: Scrivi un test unit che chiama questa parte del codice.

Suppongo che il codice funzionerà correttamente se utilizzato separatamente. Puoi quindi testare gli altri tuoi moduli allo stesso modo, fino a quando non scopri cosa causa il bug.

Anche usare Valgrind, come altri hanno suggerito, è un'ottima idea.

Il codice è problematico. Se malloc restituisce NULL, questo caso non viene gestito correttamente nel tuo codice. Supponi semplicemente che la memoria sia stata allocata per te quando in realtà non lo è stata. Ciò può causare il danneggiamento della memoria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top