Что такое ошибка glibc free/malloc/realloc недопустимая ошибка следующего размера/недопустимого указателя и как ее исправить?

Вы, скорее всего, видите этот вопрос, потому что ваш вопрос был закрыт как дубликат этого. Для умеренно полного списка связанных вопросов, пожалуйста, см. Длинный список возможных дубликатов - Ограничение памяти C и ограничения обхода в Meta Stack Overflow.


Пример Вопрос

От бесплатно char *: неверный следующий размер (быстрый), заданный noobie на 2014-04-11.

Я освобождаю char* после процесса конкатенации, но получаю эту ошибку:

free(): invalid next size (fast): 0x0000000001b86170

Это мой код:

void concat(stringList *list) {
    char *res = (char*)malloc(sizeof(char*));

    strcpy(res, list->head->string);

    list->tmp = list->head->next;
    while (list->tmp != NULL) {
        strcat(res, ",");
        strcat(res, list->tmp->string);
        list->tmp = list->tmp->next;
    }

    printf("%s\n", res);
    free(res);
}

Общий вопрос

При запуске моей программы я вижу сообщение об ошибке следующего вида:

*** glibc detected *** ./a.out: free(): corrupted unsorted chunks: 0x12345678 ***

Подробная информация может содержать любое из следующих значений после *** glibc detected *** и имени программы, а за сообщением следует шестнадцатеричный адрес (отображается как 0x12345678) и другой ***:

  • free(): corrupted unsorted chunks: 0x12345678
  • free(): invalid next size (fast): 0x12345678
  • free(): invalid next size (normal): 0x12345678
  • free(): invalid pointer: 0x12345678
  • free(): invalid size: 0x12345678
  • malloc(): corrupted unsorted chunks: 0x12345678
  • malloc(): corrupted unsorted chunks 2: 0x12345678
  • malloc(): memory corruption: 0x12345678
  • malloc(): memory corruption (fast): 0x12345678
  • malloc(): smallbin double linked list corrupted: 0x12345678
  • munmap_chunk(): invalid pointer: 0x12345678
  • realloc(): invalid next size (fast): 0x12345678
  • realloc(): invalid old size (fast): 0x12345678
  • realloc(): invalid pointer: 0x12345678
  • corrupted double-linked list: 0x12345678

Это происходит при вызове функции frobnicate(); что не так с этой функцией?

Ответ 1

Ответ для примера Вопрос

unwind дал принятый ответ на примерный вопрос:

Неверный код.

Вы выделяете пространство для одного указателя (malloc(sizeof(char*))), но не символов. Вы переписываете выделенное пространство со всеми строками, вызывая поведение undefined (в данном конкретном случае, искажая malloc() данные бухгалтерского учета).

Вам не нужно выделять пространство для указателя (res); это локальная переменная. Вы должны выделить место для всех символов, которые вы хотите сохранить по адресу, удерживаемому указателем.

Поскольку вы собираетесь перемещаться по списку, чтобы найти строки для конкатенации, вы не можете знать общий размер аванса. Вам нужно будет сделать два прохода над списком: один для суммирования strlen() каждой строки, затем выделите это плюс для разделителя и терминатора, затем еще один проход, когда вы на самом деле выполняете конкатенацию.

Общий ответ

То, что вы видите, является результатом коррупции во внутренних структурах распределителя glibc. Когда вы назначаете или освобождаете динамическую память, распределитель должен управлять памятью, зарезервированной ею из ОС, и, в зависимости от запрошенного вами действия, найдите новый кусок для раздачи, сортируйте освобожденный кусок в список тех, которые он может передать позже или вернуть память операционной системе. Эти сообщения об ошибках показывают, что структуры данных, которые он использует для управления этой функциональностью, повреждены.

Все эти ошибки означают, что часть вашего кода изменила память, которую она не использовала, вызывая поведение undefined. Скорее всего, это результат перезаписывания некоторой памяти немного раньше в вашей программе, и вполне возможно, что ошибка не лежит в функции frobnicate().

Да, это означает, что ошибка может быть в любом месте вашей программы или сторонних библиотек, которые вы используете.

Это, вероятно, не очень хороший вопрос для. Если у вас нет простого простого воспроизведения вашей проблемы, это сообщество не сможет вам помочь. Причина ошибки может быть в любом месте вашего кода (и очень часто не в функции, где обнаружена ошибка), и это может быть в коде, который мы не видим. Qaru не является совместным отладочным сайтом. Даже когда кто-то может найти недостаток в вашем коде, маловероятно, что ваш конкретный вопрос когда-нибудь поможет любому будущему посетителю.

Общие причины

  • Использовать после бесплатного.. После этого вы освободили или удалили некоторую память и записали ее, перезаписав структуру glibc для ведения бухгалтерии.
  • Ошибка Off-by-N.. Вы пишете N байтов после выделенного фрагмента в нераспределенную память, которую glibc использует внутри своей учетной записи.
  • Неинициализированные указатели. Вы не инициализируете указатель. По совпадению это указывает на некоторую память, зарезервированную glibc, но не выделенную вашей программой, и вы пишете ей.
  • Выделение неправильного пространства. Это может быть потому, что вы написали long *data = malloc(number * 4) вместо long *data = malloc(number * sizeof(long)); или (лучше) long *data = malloc(number * sizeof(*data));. Есть много других способов ошибочного вычисления размера. Другой распространенный - забыть учитывать символ нулевого терминатора в конце строки: char *copy = malloc(strlen(str)); вместо char *copy = malloc(strlen(str)+1);.

Теперь вам нужно свернуть рукава и отладить эту проблему

Нет простого ответа, что искать или что исправить. Ни одна синтаксическая конструкция, которую вы использовали неправильно. Причиной этой ошибки может быть буквально тысячи разновидностей.

Инструменты

  • valgrind Инструмент, созданный в основном для поиска именно таких ошибок. Если он не может найти что-либо, убедитесь, что вы используете последнюю версию, и вы также пытаетесь включить включенный инструмент exp-sgcheck. Если вы используете многопоточный код, причина также может быть связана с состоянием гонки, поэтому вы можете попробовать включенные проверки состояния гонки drd и helgrind для более глубокого понимания. На момент написания этой статьи valgrind поддерживает следующие платформы:
    • X86/Linux,
    • AMD64/Linux,
    • ARM/Linux,
    • PPC32/Linux,
    • PPC64/Linux,
    • S390X/Linux,
    • MIPS32/Linux,
    • MIPS64/Linux,
    • ARM/Android (2.3.x и более поздние версии),
    • X86/Android (4.0 и более поздние версии),
    • X86/Дарвин и
    • AMD64/Darwin (Mac OS X 10.7 с ограниченной поддержкой 10.8).
  • purify Подобный инструмент для valgrind, но коммерческий и нацеленный на другой набор платформ.
  • AddressSanitizer Подобный инструмент, но интегрированный в компилятор toolchain (gcc и clang).
  • efence Снижение замены распределителя, которое попытается сбой вашей программы раньше, чтобы вы могли найти с обычным отладчиком, где произошла запись в недопустимую память.
  • dmalloc библиотека с аналогичной целью, как функция.

Требуется дополнительная помощь

Если вы не можете решить свою проблему, используя один из этих инструментов, вы должны попытаться создать MCVE (Как создать минимальный, завершенный и проверенный пример?) или, что то же самое, SSCCE (Short, Self Contained, Correct (Compilable), Example).

Не забудьте работать с копией вашего кода, потому что для создания MCVE вам необходимо безжалостно удалить код, который не поможет воспроизвести проблему. Использование VCS (системы контроля версий) для оказания помощи - хорошая идея; вы можете записывать промежуточные этапы, чтобы свести проблему к минимуму. Это может быть новый отсекающий репозиторий, чтобы уменьшить вашу проблему до управляемого размера.

С хорошим модульным дизайном для вашего кода, должно быть относительно легко создать MCVE. Возможно, у вас уже есть unit test, который лучше подходит для подачи в один из указанных выше инструментов. Вы также можете просто создать тот, который позже может служить регрессионным тестом для этой ошибки.