Pergunta

Eu tenho um bug ímpar no meu programa, parece -me que o malloc () está causando um Sigsegv, que no que diz respeito ao meu entendimento não faz sentido. Estou usando uma biblioteca chamada SimClist para listas dinâmicas.

Aqui está uma estrutura que é mencionada mais tarde:

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

E aqui está o 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 é onde o programa falha, aqui está o 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;
}

a linha l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * é onde o Sigsegv é causado de acordo com o rastreamento da pilha. Estou usando o GDB/Nemiver para depuração, mas estou perdido. A primeira vez que essa função é chamada, funciona bem, mas sempre falha na segunda vez. Como o malloc () pode causar um sigsegv?

Este é o rastreamento da pilha:

#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

Qualquer ajuda ou insight é muito apreciado!

Foi útil?

Solução

malloc pode segfault, por exemplo, quando a pilha estiver corrompida. Verifique se você não está escrevendo nada além dos limites de qualquer alocação anterior.

Outras dicas

Provavelmente, a violação da memória ocorre em outra parte do seu código. Se você estiver no Linux, definitivamente deve tentar Valgrind. Eu nunca confiaria nos meus próprios programas C, a menos que passe Valgrind.

Editar: outra ferramenta útil é Cerca elétrica. Glibc também fornece o MALLOC_CHECK_ Variável ambiental para ajudar a depurar problemas de memória. Esses dois métodos não afetam tanto a velocidade de execução quanto Valgrind.

Você provavelmente o corrompeu em algum lugar antes desta chamada por um buffer estouro ou ligando free com um ponteiro que não foi alocado por malloc (ou isso já foi libertado).

Se as estruturas de dados internas usadas pelo MALLOC forem corrompidas dessa maneira, o Malloc estará usando dados inválidos e poderá travar.

Existem inúmeras maneiras de desencadear um depósito de núcleo de malloc() (e realloc() e calloc()). Esses incluem:

  • Buffer Overflow: escrevendo além do final do espaço alocado (Informações de controle de pisoteamento que malloc() estava mantendo aí).
  • Buffer Underflow: escrevendo antes do início do espaço alocado (Informações de controle de pisoteamento que malloc() estava mantendo aí).
  • Liberando memória que não foi alocada por malloc(). Em um programa m misto C e C ++, que incluiria a libertação de memória alocada em C ++ por new.
  • Liberando um ponteiro que aponta em meio caminho através de um bloco de memória alocado por malloc() - que é um caso especial do caso anterior.
  • Liberando um ponteiro que já foi libertado - o notório 'duplo livre'.

Usando uma versão diagnóstica de malloc() ou permitir diagnósticos na versão padrão do seu sistema, pode ajudar a identificar alguns desses problemas. Por exemplo, pode ser capaz de detectar pequenos fluxos e transbordamentos (porque aloca espaço extra para fornecer uma zona de buffer ao redor do espaço que você solicitou), e provavelmente pode detectar tentativas de liberdade de memória que não foi alocada ou que já foi libertada ou ponteiros no meio do espaço alocado - porque ele armazenará as informações separadamente do espaço alocado. O custo é que a versão de depuração ocupa mais espaço. Um alocador realmente bom poderá gravar os números de rastreamento e linha da pilha para dizer onde ocorreu a alocação no seu código ou onde ocorreu o primeiro livre.

Você deve tentar depurar esse código isoladamente, para ver se o problema está realmente localizado onde o segfault é gerado. (Eu suspeito que não seja).

Isso significa:

#1: Compile o código com -o0, para garantir que o GDB obtenha informações corretas sobre a numeração da linha.

#2: Escreva um teste de unidade que chama essa parte do código.

Meu palpite é que o código funcionará corretamente quando usado separadamente. Você pode testar seus outros módulos da mesma maneira, até descobrir o que causa o bug.

Usar Valgrind, como outros sugeriu, também é uma ideia muito boa.

O código é problemático. Se Malloc retornar NULL, este caso não será tratado corretamente em seu código. Você simplesmente assume que a memória foi alocada para você quando realmente não foi. Isso pode causar corrupção de memória.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top