Почему я получаю сообщение об отказе C malloc?

Я реализую алгоритм разделения и преодоления полиномов, поэтому я могу сравнить его с реализацией 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) 'не удалось. Отменено

Соответствующая строка:

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);
}

Я проверил размер с помощью fprintf, и это положительное целое число (обычно 50 в этой точке). Я попробовал позвонить malloc с простым номером, и я все еще получаю ошибку. Я просто в шоке от того, что происходит, и ничего из Google, которого я нашел до сих пор, полезно.

Есть идеи, что происходит? Я пытаюсь понять, как скомпилировать новый GCC в случае ошибки компилятора, но я действительно сомневаюсь в этом.

Ответ 1

99.9% Вероятность того, что у вас поврежденная память (избыточный или недоработанный буфер, написанный указателем после его освобождения, дважды вызываемый по одному указателю и т.д.)

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

Ответ 2

Чтобы дать вам лучшее представление о том, почему это происходит, я хотел бы немного рассказать о @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 size. Когда вы теперь будете следующим вызовом malloc, он будет смотреть на последнее место памяти, которое он вернул, посмотрите на его поле размера, перейдите к p3 + size, а затем начните выделение памяти оттуда. Однако, поскольку ваш код перезаписал size, это место памяти больше не находится после ранее выделенной памяти.

Излишне говорить, что это может разрушить хаос! Поэтому разработчики malloc ввели ряд "утверждений" или проверок, которые пытаются сделать кучу проверки здравомыслия, чтобы поймать эту (и другие проблемы), если они вот-вот произойдут. В вашем конкретном случае эти утверждения нарушаются, и поэтому malloc прерывает, сообщая вам, что ваш код должен был сделать что-то, чего он действительно не должен делать.

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

Ответ 3

Возможно, вы, вероятно, перебегаете за пределы выделенного mem. то базовый sw не поднимается на него, пока вы не вызовете malloc

Может существовать защитное значение, забитое malloc.

edit... добавлено это для справки по проверке границ

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

Ответ 4

Я получил следующее сообщение, похожее на ваше:

    program: malloc.c:2372: 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.

Сделал ошибку при вызове метода до, используя malloc. Неожиданно перезаписал знак умножения '*' с помощью '+', обновляя коэффициент после оператора sizeof() при добавлении поля в массив без знака char.

Вот код, ответственный за ошибку в моем случае:

    UCHAR* b=(UCHAR*)malloc(sizeof(UCHAR)+5);
    b[INTBITS]=(some calculation);
    b[BUFSPC]=(some calculation);
    b[BUFOVR]=(some calculation);
    b[BUFMEM]=(some calculation);
    b[MATCHBITS]=(some calculation);

В другом методе позже я снова использовал malloc и вывел сообщение об ошибке, показанное выше. Вызов был (достаточно простой):

    UCHAR* b=(UCHAR*)malloc(sizeof(UCHAR)*50);

Подумайте, используя знак "+" на первом вызове, который приводит к ошибочному исчислению в сочетании с немедленной инициализацией массива после (перезаписи памяти, которая не была выделена массиву), вызвала некоторую путаницу malloc. Поэтому 2-й вызов поступил не так.

Ответ 5

Мое альтернативное решение для использования Valgrind:

Я очень счастлив, потому что я только что помог моему другу отладить программу. У его программы была именно эта проблема (malloc() вызывающая прерывание) с тем же сообщением об ошибке из GDB.

Я скомпилировал его программу, используя дезинфицирующее средство

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 итог: попробуйте адрес -fsanitize=address GCC, это может быть очень полезно при устранении проблем с памятью.

Ответ 6

Мы получили эту ошибку, потому что забыли умножить на sizeof (int). Обратите внимание, что аргумент malloc (..) - это количество байтов, а не количество машинных слов или что-то еще.

Ответ 7

Я переносил одно приложение из Visual C в gcc поверх Linux, и у меня была та же проблема с

malloc.c: 3096: sYSMALLOc: утверждение с использованием gcc на UBUNTU 11.

Я переместил тот же код в дистрибутив Suse (на другом компьютере), и у меня нет никаких проблем.

Я подозреваю, что проблемы не в наших программах, а в собственном libc.

Ответ 8

У меня такая же проблема, я снова использовал malloc над n в цикле для добавления новых строковых данных char *. я столкнулся с той же проблемой, но после освобождения выделенной памяти void free() была отсортирована