Я реализую полиномиальный алгоритм «разделяй и властвуй», поэтому могу сравнить его с реализацией OpenCL, но не могу приступить malloc
к работе. Когда я запускаю программу, она выделяет кучу данных, кое-что проверяет, а затем отправляет size/2
в алгоритм. Затем, когда я malloc
снова нажимаю на линию, она выплевывает это:
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
Речь идет о следующей строке:
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);
}
Я проверил размер с помощью a fprintf
, и это положительное целое число (обычно 50 в этот момент). Я пытался позвонить malloc
по простому номеру, но все равно получаю сообщение об ошибке. Я просто не понимаю, что происходит, и ничего от Google, которое я нашел до сих пор, не помогает.
Есть идеи, что происходит? Я пытаюсь понять, как скомпилировать новый GCC, если это ошибка компилятора, но я действительно сомневаюсь в этом.
Ответы:
Вероятность 99,9%, что вы испортили память (переполнение или недостаточное заполнение буфера, запись в указатель после того, как он был освобожден, дважды вызванная свободная память для одного и того же указателя и т. Д.)
Запустите свой код под Valgrind, чтобы увидеть, где ваша программа сделала что-то неправильно.
источник
Чтобы вы лучше понимали, почему это происходит, я хотел бы немного расширить ответ @ r-samuel-klatchko.
Когда вы звоните
malloc
, то, что происходит на самом деле, немного сложнее, чем просто дать вам кусок памяти для игры. Под капотомmalloc
также хранится некоторая служебная информация о памяти, которую он вам предоставил (что наиболее важно, ее размер), чтобы при вызовеfree
он знал такие вещи, как объем памяти, который нужно освободить. Эта информация обычно сохраняется прямо перед тем, как ячейка памяти возвращается вамmalloc
. Более исчерпывающую информацию можно найти в Интернете ™ , но (самая) основная идея примерно такая:+------+-------------------------------------------------+ + size | malloc'd memory + +------+-------------------------------------------------+ ^-- location in pointer returned by malloc
Основываясь на этом (и значительно упрощая), когда вы вызываете
malloc
, он должен получить указатель на следующую доступную часть памяти. Один очень простой способ сделать это - посмотреть на предыдущий бит памяти, который он отдал, и переместитьsize
байты дальше вниз (или вверх) в памяти. В этой реализации ваша память будет выглядеть примерно так после выделенияp1
,p2
иp3
:Итак, что вызывает вашу ошибку?
Что ж, представьте, что ваш код ошибочно записывает объем памяти, который вы выделили (либо потому, что вы выделили меньше, чем вам нужно, что было вашей проблемой, либо потому что вы используете неправильные граничные условия где-то в своем коде). Предположим, что ваш код пишет так много данных ,
p2
что он начинает перезаписывать , что вp3
«ssize
поле. Когда вы теперь вызовете следующий вызовmalloc
, он будет смотреть на последнее возвращенное место в памяти, смотреть на его поле размера, переместитьсяp3 + size
и затем начать выделение памяти оттуда. Однако, поскольку ваш код был перезаписанsize
, эта ячейка памяти больше не находится после ранее выделенной памяти.Излишне говорить, что это может нанести серьезный ущерб! Поэтому разработчики
malloc
внедрили ряд «утверждений» или проверок, которые пытаются выполнить несколько проверок работоспособности, чтобы отловить это (и другие проблемы), если они вот-вот произойдут. В вашем конкретном случае эти утверждения нарушаются и, таким образом,malloc
прерываются, сообщая вам, что ваш код собирался сделать что-то, чего на самом деле делать не должно.Как было сказано ранее, это грубое упрощение, но его достаточно, чтобы проиллюстрировать суть дела. Реализация glibc
malloc
состоит из более чем 5 тыс. Строк, и было проведено значительное количество исследований о том, как построить хорошие механизмы распределения динамической памяти, поэтому охватить все это в SO-ответе невозможно. Надеюсь, это дало вам некоторое представление о том, что на самом деле вызывает проблему!источник
Мое альтернативное решение для использования Valgrind:
Я очень счастлив, потому что только что помог другу отладить программу. В его программе была точно такая же проблема (
malloc()
вызывающая прерывание) с тем же сообщением об ошибке от GDB.Я скомпилировал его программу с помощью Address Sanitizer с
gcc -Wall -g3 -fsanitize=address -o new new.c ^^^^^^^^^^^^^^^^^^
А потом побежал
gdb new
. Когда программа завершается по причине,SIGABRT
вызванной последующимmalloc()
, печатается много полезной информации:================================================================= ==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)
Давайте посмотрим на вывод, особенно на трассировку стека:
В первой части говорится о недопустимой операции записи в
new.c:59
. Эта строка гласитmemset(len,0,sizeof(int*)*p); ^^^^^^^^^^^^
Во второй части говорится, что создается память, в которой произошла некорректная запись
new.c:55
. Эта строка гласитif(!(len=(int*)malloc(sizeof(int)*p))){ ^^^^^^^^^^^
Вот и все. У меня ушло меньше получаса, чтобы найти ошибку, которая несколько часов сбивала с толку моего друга. Ему удалось определить местонахождение сбоя, но последующий
malloc()
вызов потерпел неудачу, так как не смог обнаружить эту ошибку в предыдущем коде.Подведем итоги: попробуйте
-fsanitize=address
GCC или Clang. Это может быть очень полезно при отладке проблем с памятью.источник
Вероятно, вы выходите за пределы выделенной памяти. тогда базовый sw не улавливает его, пока вы не вызовете malloc
Может быть сбито охранное значение, которое перехватывается malloc.
изменить ... добавил это для справки по проверке границ
http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html
источник
Я получил следующее сообщение, похожее на ваше:
Раньше совершал ошибку при вызове метода при использовании malloc. Ошибочно заменял знак умножения '*' на '+' при обновлении множителя после sizeof () - оператора при добавлении поля в массив unsigned char.
Вот код, ответственный за ошибку в моем случае:
Позже в другом методе я снова использовал malloc, и он выдал сообщение об ошибке, показанное выше. Звонок был (достаточно простой):
Подумайте об использовании знака «+» при первом вызове, который приведет к неправильному расчету в сочетании с немедленной инициализацией массива после (перезапись памяти, которая не была выделена для массива), внесла некоторую путаницу в карту памяти malloc. Поэтому 2-й звонок пошел не так.
источник
Мы получили эту ошибку, потому что забыли умножить на sizeof (int). Обратите внимание, что аргумент malloc (..) - это количество байтов, а не количество машинных слов или что-то еще.
источник
У меня та же проблема, я снова использовал malloc над n в цикле для добавления новых строковых данных char *. Я столкнулся с той же проблемой, но после выпуска выделенной памяти
void free()
проблемы были отсортированыисточник
Я переносил одно приложение с Visual C на gcc через Linux, и у меня была такая же проблема с
Я переместил тот же код в дистрибутив Suse (на другой компьютер), и у меня нет никаких проблем.
Подозреваю, что проблемы не в наших программах, а в собственной libc.
источник