Estou implementando um algoritmo polinomial de divisão e conquista para que possa compará-lo com uma implementação do OpenCL, mas não consigo malloc
trabalhar. Quando executo o programa, ele aloca um monte de coisas, verifica algumas coisas e envia o size/2
para o algoritmo. Então, quando eu acerto a malloc
linha novamente, ele cospe o seguinte:
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
A linha em questão é:
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);
}
Eu verifiquei o tamanho com um fprintf
, e é um número inteiro positivo (normalmente 50 nesse ponto). Também tentei ligar malloc
com um número simples e ainda recebo o erro. Estou simplesmente perplexo com o que está acontecendo, e nada do Google que encontrei até agora é útil.
Alguma ideia sobre o que se passa? Estou tentando descobrir como compilar um GCC mais recente no caso de ser um erro do compilador, mas eu realmente duvido.
Respostas:
99,9% de probabilidade de que você tenha corrompido a memória (excesso ou falta de fluxo em um buffer, gravou em um ponteiro depois que ele foi liberado, chamado de free duas vezes no mesmo ponteiro, etc.)
Execute seu código em Valgrind para ver onde seu programa fez algo incorreto.
fonte
Para lhe dar uma compreensão melhor de por que isso acontece, gostaria de expandir um pouco a resposta de @ r-samuel-klatchko.
Quando você liga
malloc
, o que realmente está acontecendo é um pouco mais complicado do que apenas dar a você um pedaço de memória para brincar. Sob o capô,malloc
também mantém algumas informações de manutenção sobre a memória que forneceu (mais importante, seu tamanho), para que, quando você ligarfree
, ele saiba coisas como quanta memória deve ser liberada. Essas informações são normalmente mantidas imediatamente antes do local da memória retornado a você pormalloc
. Informações mais completas podem ser encontradas na internet ™ , mas a ideia (muito) básica é mais ou menos assim:+------+-------------------------------------------------+ + size | malloc'd memory + +------+-------------------------------------------------+ ^-- location in pointer returned by malloc
Com base nisso (e simplificando muito as coisas), quando você chama
malloc
, ele precisa obter um ponteiro para a próxima parte da memória que está disponível. Uma maneira muito simples de fazer isso é examinar o bit de memória anterior que ele cedeu e mover ossize
bytes para baixo (ou para cima) na memória. Com esta implementação, você acaba com sua memória parecida com isto após a alocaçãop1
,p2
ep3
:Então, o que está causando o seu erro?
Bem, imagine que seu código grava erroneamente além da quantidade de memória que você alocou (ou porque você alocou menos do que o necessário como era o seu problema ou porque está usando as condições de limite erradas em algum lugar do seu código). Diga seu código escreve tantos dados para
p2
que ele começa a substituir o que está emp3
'ssize
campo. Na próxima chamadamalloc
, ele irá olhar para a última localização de memória que retornou, olhar para seu campo de tamanho, mover parap3 + size
e então começar a alocar memória de lá. Como seu código foi sobrescritosize
, no entanto, esse local de memória não é mais posterior à memória alocada anteriormente.Nem é preciso dizer que isso pode causar estragos! Os implementadores de
malloc
, portanto, colocaram uma série de "asserções", ou verificações, que tentam fazer uma série de verificações de sanidade para detectar este (e outros problemas) se eles estiverem prestes a acontecer. No seu caso específico, essas asserções são violadas e, portantomalloc
, são canceladas, informando que seu código estava prestes a fazer algo que realmente não deveria estar fazendo.Como afirmado anteriormente, esta é uma simplificação grosseira, mas é suficiente para ilustrar o ponto. A implementação glibc de
malloc
tem mais de 5k linhas e tem havido uma quantidade substancial de pesquisas sobre como construir bons mecanismos de alocação de memória dinâmica, portanto, cobrir tudo em uma resposta SO não é possível. Espero que isso tenha lhe dado uma visão do que realmente está causando o problema!fonte
Minha solução alternativa para usar Valgrind:
Estou muito feliz porque acabei de ajudar meu amigo a depurar um programa. Seu programa tinha exatamente este problema (
malloc()
causando aborto), com a mesma mensagem de erro do GDB.Compilei seu programa usando Address Sanitizer com
gcc -Wall -g3 -fsanitize=address -o new new.c ^^^^^^^^^^^^^^^^^^
E então correu
gdb new
. Quando o programa é encerrado porSIGABRT
causado em um subsequentemalloc()
, uma série de informações úteis são impressas:================================================================= ==407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8 WRITE of size 104 at 0x6060000000b4 thread T0 #0 0x7ffffe49ed19 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19) #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59 #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679) 0x6060000000b4 is located 0 bytes to the right of 52-byte region [0x606000000080,0x6060000000b4) allocated by thread T0 here: #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50) #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55 #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
Vamos dar uma olhada na saída, especialmente o rastreamento de pilha:
A primeira parte diz que há uma operação de gravação inválida em
new.c:59
. Essa linha dizmemset(len,0,sizeof(int*)*p); ^^^^^^^^^^^^
A segunda parte diz que a memória em que a gravação incorreta aconteceu é criada
new.c:55
. Essa linha dizif(!(len=(int*)malloc(sizeof(int)*p))){ ^^^^^^^^^^^
É isso aí. Levei menos de meio minuto para localizar o bug que confundiu meu amigo por algumas horas. Ele conseguiu localizar a falha, mas é uma subsequente
malloc()
chamada que falhou, sem ser capaz de detectar esse erro no código anterior.Resumindo: experimente o
-fsanitize=address
do GCC ou do Clang. Pode ser muito útil ao depurar problemas de memória.fonte
Você provavelmente está ultrapassando o mem alocado em algum lugar. então o sw subjacente não pega até que você chame malloc
Pode haver um valor de proteção superado que está sendo capturado por malloc.
editar ... adicionado isto para ajuda de verificação de limites
http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html
fonte
Recebi a seguinte mensagem, semelhante à sua:
Cometeu um erro alguma chamada de método antes, ao usar malloc. Sobrescreveu erroneamente o sinal de multiplicação '*' com um '+', ao atualizar o fator após o operador sizeof () - ao adicionar um campo a um array de caracteres sem sinal.
Aqui está o código responsável pelo erro no meu caso:
Posteriormente, em outro método, usei malloc novamente e ele produziu a mensagem de erro mostrada acima. A chamada foi (bastante simples):
Pense em usar o sinal '+' - na primeira chamada, o que leva a um cálculo incorreto em combinação com a inicialização imediata do array depois (sobrescrever a memória que não foi alocada para o array), trouxe alguma confusão ao mapa de memória de malloc. Portanto, a segunda chamada deu errado.
fonte
Recebemos esse erro porque esquecemos de multiplicar por sizeof (int). Observe que o argumento para malloc (..) é um número de bytes, não um número de palavras de máquina ou qualquer outra coisa.
fonte
Eu tenho o mesmo problema, usei malloc sobre n novamente em um loop para adicionar novos dados de string char *. Eu enfrentei o mesmo problema, mas depois de liberar o
void free()
problema de memória alocada foram resolvidosfonte
Eu estava portando um aplicativo do Visual C para o gcc no Linux e tive o mesmo problema com
Mudei o mesmo código para uma distribuição Suse (em outro computador) e não tenho nenhum problema.
Suspeito que os problemas não estejam em nossos programas, mas na própria libc.
fonte