Pregunta

Tengo un error extraño en mi programa, me parece que malloc () está causando un SIGSEGV, que hasta donde yo entiendo no tiene ningún sentido. Estoy usando una biblioteca llamada simclist para listas dinámicas.

Aquí hay una estructura a la que se hace referencia más adelante:

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

Y aquí está el código:

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 es donde falla el programa, aquí está el código para 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 línea l- > spareels = (struct list_entry_s **) malloc (SIMCLIST_MAX_SPARE_ELEMS * es donde el SIGSEGV es causado de acuerdo con el seguimiento de la pila. Estoy usando gdb / nemiver para la depuración pero estoy con pérdida. La primera vez que se llama a esta función funciona bien pero siempre falla la segunda vez. ¿Cómo puede malloc () causar un SIGSEGV?

Esta es la traza de la pila:

#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

¡Cualquier ayuda o idea es muy apreciada!

¿Fue útil?

Solución

malloc puede segfault, por ejemplo, cuando el montón está dañado. Compruebe que no está escribiendo nada más allá de los límites de cualquier asignación anterior.

Otros consejos

Probablemente se produce una violación de la memoria en otra parte de su código. Si estás en Linux, definitivamente deberías probar valgrind. Nunca confiaría en mis propios programas en C a menos que pase valgrind.

EDITAR: otra herramienta útil es Cerca eléctrica . Glibc también proporciona la MALLOC_CHECK_ variable de entorno para ayudar a depurar problemas de memoria. Estos dos métodos no afectan tanto a la velocidad de carrera como a valgrind.

Probablemente haya dañado su montón antes de esta llamada por un desbordamiento del búfer o llamando a free con un puntero que no fue asignado por malloc (o que ya estaba liberado).

Si las estructuras de datos internas utilizadas por malloc se corrompen de esta manera, malloc está utilizando datos no válidos y podría bloquearse.

Hay miles de formas de activar un volcado de núcleo desde malloc () (y realloc () y calloc () ). Estos incluyen:

  • Desbordamiento de búfer: escritura más allá del final del espacio asignado (pisoteando la información de control que malloc () mantenía allí).
  • Desbordamiento de búfer: escritura antes del inicio del espacio asignado (pisoteando la información de control que malloc () mantenía allí).
  • Liberando memoria que no fue asignada por malloc () . En un programa mixto de C y C ++, eso incluiría liberar memoria asignada en C ++ por new .
  • Liberación de un puntero que apunta en parte a través de un bloque de memoria asignado por malloc () , que es un caso especial del caso anterior.
  • Liberando un puntero que ya estaba liberado: el notorio 'doble libre'.

Usar una versión de diagnóstico de malloc () o habilitar diagnósticos en la versión estándar de su sistema puede ayudar a identificar algunos de estos problemas. Por ejemplo, puede detectar pequeños desbordamientos y desbordamientos (porque asigna espacio adicional para proporcionar una zona de amortiguación alrededor del espacio que solicitó), y probablemente puede detectar intentos de liberar memoria que no estaba asignada o que ya estaba liberada o punteros a mitad del espacio asignado, porque almacenará la información por separado del espacio asignado. El costo es que la versión de depuración ocupa más espacio. Un asignador realmente bueno podrá registrar el seguimiento de la pila y los números de línea para indicarle dónde ocurrió la asignación en su código, o dónde ocurrió la primera libre.

Debería intentar depurar este código de forma aislada, para ver si el problema se encuentra realmente donde se genera el segfault. (Sospecho que no lo es).

Esto significa:

# 1: compile el código con -O0, para asegurarse de que gdb obtenga la información correcta de numeración de línea.

# 2: Escriba una prueba unitaria que llame a esta parte del código.

Supongo que el código funcionará correctamente cuando se use por separado. Luego puede probar sus otros módulos de la misma manera, hasta que descubra qué causa el error.

Usar Valgrind, como han sugerido otros, también es una muy buena idea.

El código es problemático. Si malloc devuelve NULL, este caso no se maneja correctamente en su código. Simplemente asume que se le ha asignado memoria cuando en realidad no se ha asignado. Esto puede causar daños en la memoria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top