Чому я отримую помилку про твердження C malloc?


85

Я впроваджую поліноміальний алгоритм поділу та завоювання, щоб я міг порівняти його з реалізацією 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 на випадок помилки компілятора, але я справді сумніваюся в цьому.


Я підозрюю, що проблема насправді в рядку перед цим. Можливо, подвійний безкоштовний?
Mitch Wheat

3-й рядок у програмі: int * mult (int size, int * a, int * b) {int * out, i, j, * tmp1, * tmp2, * tmp3, * tmpa1, * tmpa2, * tmpb1, * tmpb2 , d, * res1, * res2; fprintf (stdout, "розмір:% d \ n", розмір); out = (int *) malloc (sizeof (int) * size * 2);
Кріс

Відповіді:


98

99,9% ймовірність того, що у вас пошкоджена пам’ять (надмірна чи недостатня витрата буфера, запис у вказівник після його звільнення, двічі виклик вільним на одному вказівнику тощо)

Запустіть свій код під Valgrind, щоб побачити, де ваша програма зробила щось неправильне.


1
виправлений. Вальгрінд чітко допоміг. Я переписав свій старий код MATLAB неправильно і мав цикл for, який повторювався над j, потім всередині нього робився j ++, який більшість переписував масив, на якому він писав, і якось призводив до збою malloc. Дякую за допомогу!
Кріс

Valgrind був лише інструментом, який мені потрібен, щоб зрозуміти, що відбувається, коли я отримав цю помилку. Дякуємо, що згадали.
alexwells

77

Щоб краще зрозуміти, чому це трапляється, я хотів би трохи розширити відповідь @ r-samuel-klatchko.

Коли ви телефонуєте malloc, те, що насправді відбувається, стає дещо складнішим, ніж просто надання вам частини пам’яті для гри. Під капотом mallocтакож зберігається деяка інформація про ведення домашнього господарства про дану вам пам’ять (найголовніше - її розмір), щоб, коли ви телефонуєте free, він знав такі речі, як кількість звільненої пам'яті. Ця інформація зазвичай зберігається безпосередньо перед місцем пам'яті, яке вам повернув malloc. Більш вичерпну інформацію можна знайти в Інтернеті ™ , але (дуже) основна ідея приблизно така:

+------+-------------------------------------------------+
+ size |                  malloc'd memory                +
+------+-------------------------------------------------+
       ^-- location in pointer returned by malloc

Спираючись на це (і значно спрощуючи речі), коли ви телефонуєте malloc, йому потрібно отримати вказівник на наступну частину доступної пам'яті. Один дуже простий спосіб зробити це - переглянути попередній біт пам'яті, який він віддав, і перемістити sizeбайти далі (або вгору) в пам’яті. За допомогою цієї реалізації ваша пам’ять виглядає приблизно так після розподілу p1, p2і p3:

+------+----------------+------+--------------------+------+----------+
+ size |                | size |                    | size |          +
+------+----------------+------+--------------------+------+----------+
       ^- p1                   ^- p2                       ^- p3

Отже, у чому причина вашої помилки?

Ну, уявіть, що ваш код помилково записує обсяг пам'яті, який ви виділили (або тому, що ви виділили менше, ніж потрібно, як було вашою проблемою, або тому, що ви використовуєте неправильні граничні умови десь у своєму коді). Припустимо, що ваш код пише так багато даних , p2що він починає перезаписувати , що в p3«s sizeполе. Коли ви перейдете до наступного дзвінка malloc, він перегляне останнє місце пам'яті, яке він повернув, перегляне поле його розміру, перейде до, p3 + sizeа потім розпочне розподіл пам'яті звідти. Оскільки ваш код перезаписано size, однак це місце в пам'яті більше не відповідає раніше виділеній пам'яті.

Що й казати, це може зруйнувати хаос! Тому розробники mallocвнесли ряд "тверджень", або перевірок, які намагаються зробити купу перевірки розумності, щоб зловити цю (та інші проблеми), якщо вони мають відбутися. У вашому конкретному випадку ці твердження порушуються, а отжеmalloc перериваються, повідомляючи вам, що ваш код збирався зробити те, чого насправді не повинен робити.

Як уже зазначалося, це є грубим спрощенням, але цього достатньо, щоб проілюструвати суть. Реалізація glibc - mallocце понад 5 тис. Рядків, і було проведено значні обсяги досліджень, як побудувати хороші механізми динамічного розподілу пам’яті, тому охопити все це у відповіді SO неможливо. Сподіваємось, це дало вам трохи уявлення про те, що насправді викликає проблему!


14

Моє альтернативне рішення використання 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=addressGCC або Clang. Це може бути дуже корисно при налагодженні проблем із пам'яттю.


1
Ви щойно врятували мені життя.
Нейт Саймер,

2

Ви, мабуть, перевищуєте межі виділеної меми. тоді основний sw не підхоплює його, поки ви не зателефонуєте malloc

Може бути охоронне значення, яке перекрито malloc.

редагувати ... додав це для довідки щодо перевірки меж

http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html


2

Я отримав таке повідомлення, подібне до вашого:

    програма: malloc.c: 2372: sysmalloc: Твердження `(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) 'не вдалося.

Помилився деякий виклик методу раніше, коли використовував malloc. Помилково переписав знак множення '*' на '+' під час оновлення коефіцієнта після оператора sizeof () - оператора при додаванні поля до беззнакового масиву символів.

Ось код, який відповідає за помилку в моєму випадку:

    UCHAR * b = (UCHAR *) malloc (розмір (UCHAR) +5);
    b [INTBITS] = (деякий розрахунок);
    b [BUFSPC] = (деякий розрахунок);
    b [BUFOVR] = (деякий розрахунок);
    b [BUFMEM] = (деякий розрахунок);
    b [MATCHBITS] = (деякий розрахунок);

Іншим методом пізніше я знову використав malloc, і він видав повідомлення про помилку, показане вище. Дзвінок був (досить простий):

    UCHAR * b = (UCHAR *) мальлок (розмір (UCHAR) * 50);

Подумайте, що використання знака '+' під час 1-го дзвінка, що призводить до неправильного обчислення в поєднанні з негайною ініціалізацією масиву після (перезапис пам'яті, яка не була виділена в масив), внесе певну плутанину в карту пам'яті malloc. Тому другий дзвінок помилився.


0

Ми отримали цю помилку, оскільки забули помножити на sizeof (int). Зверніть увагу, що аргументом malloc (..) є кількість байтів, а не кількість машинних слів чи що інше.


0

у мене така сама проблема, я знову використав malloc over n у циклі для додавання нових даних char * string. я зіткнувся з тією ж проблемою, але після звільнення виділену void free()проблему пам'яті було відсортовано


-2

Я переносив одну програму з Visual C на gcc через Linux, і у мене була та ж проблема

malloc.c: 3096: sYSMALLOc: Твердження за допомогою gcc на UBUNTU 11.

Я перемістив той самий код у дистрибутив Suse (на іншому комп’ютері), і у мене не виникає проблем.

Я підозрюю, що проблеми не в наших програмах, а у власному libc.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.