Ошибка heap corruption detected

MayaNash, в твоем сообщении об ошибке есть полезная информация:

«Normal block» — это блок памяти, выделенный new, malloc или calloc.

«application wrote to memory after end of heap buffer» — это значит, что
приложение при записи вылезло за пределы буфера.

Ловить такую ошибку можно по-разному.

Во-первых, для начала можно врубить на максимум все возможности отладочной CRT
(debug CRT) и понаставить проверок через каждые 5 строчек кода, статья по теме есть на RSDN:

Обнаружение и локализация утечек памяти
http://rsdn.org/article/vcpp/leaks.xml

Во-вторых, можно временно заменить new/malloc/calloc на VirtualAlloc, сделав «забор»:
первая страница (страницы) памяти под буфер выделяются с атрибутами PAGE_READWRITE
(чтение + запись), а защита самой последней страницы меняется (через VirtualProtect)
на PAGE_NOACCESS (нет доступа). Причем адрес буфера делается таким, чтобы конец
буфера упирался сразу же в страницу с PAGE_NOACCESS. В этом случае при попытке
что-то записать или прочитать за пределами буфера сразу вылетит исключение
STATUS_ACCESS_VIOLATION, ну а далее можно подключать отладчик и смотреть,
где вылезли за границу.

Есть специальные аллокаторы, которые делают всю эту работу (и еще много чего),
конкретные не посоветую, ибо сам пользуюсь такими вещами редко.

Динамический массив в языке C++ имеет два значения: массив переменного размера(т.е. способным к добавлению и удалению в нём элементов) и массив, который мы разместили в куче(heap). В данном случае вы используете второй вид динамического массива, который сам по себе не меняет своих размеров.

Когда мы хотим считать и записать элементы массива, то у нас стоит выбор какой использовать: статический или динамический(1 или 2). Если количество элементов фиксировано(т.е. мы изначально знаем), то под это отлично подойдёт обычный статический массив, а если же количество элементов вводится с клавиатуры, то мы используем динамический, т.к. по стандарту в языке C++ количество элементов в статическом массиве должно быть известно в момент компиляции, никак не исполнения.
В вашем случае, как я понял, количество элементов фиксировано и равно 10. Тогда и вовсе динамический массив никак не обязателен.

Распишу решение в 3-х видах: с использованием статического и динамического 1-го и 2-го вида.

Статический(неспособный к растягиванию массив, выделенный в stack):

int main()
{
    constexpr int ARR_SIZE = 10;
     arr[ARR_SIZE];
    for(int i = 0; i < ARR_SIZE; ++i)
        std::cin >> arr[i];

    //обрабатываем элементы массива
    ...
    return 0;
}

Динамический(неспособный к растягиванию массив в heap):

#include <iostream>
#include <vector>

int main()
{
    int numbersInArray;
    std::cout << "Enter number of elements: ";
    std::cin >> numbersInArray;
    double *arr = new double[numbersInArray];
    for(int i = 0; i < numbersInArray; ++i)
        cin >> arr[i];
    //обрабатываем элементы массива
    ...
    return 0;
}

Динамический(cпособный к растягиванию массив, внутри сам выделен в heap):

#include <iostream>
#include <vector>

int main()
{
    std::vector < double > arr;
    int numbersInArray;
    std::cout << "Enter number of elements: ";
    std::cin >> numbersInArray;
    for(int i = 0; i < numbersInArray; ++i)
    {
        double temp_variable;
        cin >> temp_variable;
        arr.push_back(temp_variable);
    }
    //обрабатываем элементы массива
    ...
    return 0;
}

  • Remove From My Forums
  • Question

  • Hi,

    I wouldn’t be asking this but this problem sometimes occurs directly after the line..

    int main(int argc, char **argv[])
    {
    PWCHAR var = (PWCHAR) malloc ((sizeof(«some\string») * sizeof(WCHAR)) + sizeof(WCHAR));

    «HEAP CORRUPTION DETECTED after normal block (#60) at 0x00000000xxxxxxxx.»
    «CRT detected the application wrote to memory after the end of the heap buffer.»

    The problem never always occurs the same line and sometimes — usually — when I run through the code step by step (F10) lines are executed but the arrow jumps past lines unless I set a specific breakpoint on the line.

    Previously another error that has occurred has been a write to invalid memory. (Error — 0x00000005, ACCESS_DENIED)

    The code seems fine when compiled as 32bit (no problems have ever occurred.) but the problems certainly occur when compiled as 64bit.

    I would like to know if it is possible that code that has been compiled has somehow been corrupted and is causing this error. I ask this only because I have had the HEAP CORRUPTION error occurred directly after the first run statement.

    Thankyou, I really need the help.

Answers

  • Heap corruptions are caused by writing too much to a memory buffer, and that is never a compiler error.

    Heap corruptions only manifest the next time you try to do something with the heap itself, like allocate more memory or free a block of memory, so it wouldn’t occur after you overwrite the end of the buffer.

    As for the debugger jumping past lines, is your configuration set to release? When it optimises code, it may remove lines completely. The debugger will just not go onto those lines. If you want the best possible debug experience, make sure it is set to the
    debug configuration.

    For a simple way of causing a heap corruption, try the following code. It will always trigger on the free line.

    int wmain()
    {
    	wchar_t *mystr = (wchar_t*)malloc(24);
    
    	wcscpy(mystr, L"a longer string");
    
    	free(mystr); //will break here
    	mystr = nullptr;
    
    	return 0;
    }

    This causes a heap corruption because obviously the buffer can only store 12 characters (including the null terminator) and you copy more than that to the buffer. The obvious way to fix this is to increase the size of the buffer.

    If you want more help though, provide code. Either your actual code or a small sample that reproduces the same issue.


    This is a signature

    Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts
    is to aid in the learning process.

    Do you want Visual Studio 11 Express to be freely installable on Windows 7 and able to write regular C++ applications? Please vote for

    this.

    • Marked as answer by

      Friday, May 11, 2012 5:38 AM

    • Unmarked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:39 AM
    • Marked as answer by
      Helen Zhao
      Thursday, May 17, 2012 3:25 AM

  • HEAP CORRUPTION DETECTED is usually caused by using bad pointers or indexes in some previously executed code.  I.e., not by the line of code that produces the message. Your malloc call just gives the heap checker an opportunity to check for heap damage
    caused by previous operations.

    If you have constructors of global objects they run before main(). So that would be a good place to look for trouble.

    • Marked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:38 AM
    • Unmarked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:39 AM
    • Marked as answer by
      Helen Zhao
      Thursday, May 17, 2012 3:25 AM

  • Hi,

    I wouldn’t be asking this but this problem sometimes occurs directly after the line..

    int main(int argc, char **argv[])

    It is probably not related to your problem but this is not a legal definition for main. Your second parameter can be char **argv or char *argv[] but not what you have posted.

    {
    PWCHAR var = (PWCHAR) malloc ((sizeof(«some\string») * sizeof(WCHAR)) + sizeof(WCHAR));

    «HEAP CORRUPTION DETECTED after normal block (#60) at 0x00000000xxxxxxxx.»
    «CRT detected the application wrote to memory after the end of the heap buffer.»

    <snip>

    Previously another error that has occurred has been a write to invalid memory. (Error — 0x00000005, ACCESS_DENIED)

    This inidcates you already have used a bad pointer.

    You need to show your actual code since it is obviouls the call to malloc is not that early.

    • Marked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:38 AM
    • Unmarked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:39 AM
    • Marked as answer by
      Helen Zhao
      Thursday, May 17, 2012 3:25 AM

  • You’re not helping yourself by mixing narrow string literals in your sizeof() expressions with wide string literals in your wcscpy() calls.  However, it doesn’t seem to be the underlying problem — unless your WCHAR
    is not a two byte type like wchar_t.

    You can safely replace

    PWCHAR var = (PWCHAR) malloc ((sizeof("some\string") * sizeof(WCHAR)) + sizeof(WCHAR));
    wcscpy(var, L"some\string");

    with the equivalent

    PWCHAR var = (PWCHAR) _wcsdup(L"some\string");

    Of course, you should always check for a NULL pointer from malloc() and _wcsdup().


    Answering policy: see profile.

    • Marked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:38 AM
    • Unmarked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:39 AM
    • Marked as answer by
      Helen Zhao
      Thursday, May 17, 2012 3:25 AM

  • I suggest you to use the _vsnwprintf
     function, where you specify the maximum number of characters to write. Also check if you use the “( )” parentheses correctly in
    malloc, and your msg is always compatible with arguments.

    • Marked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:39 AM
    • Unmarked as answer by
      Helen Zhao
      Friday, May 11, 2012 5:39 AM
    • Marked as answer by
      Helen Zhao
      Thursday, May 17, 2012 3:25 AM

Немного расскажу про дебажную кучу, речь пойдет о Visual Studio 2008. В остальных версиях дебажная куча выглядит примерно так же. Про другие компиляторы не знаю.

Основная мысль — дебажная куча отличается от релизной, чтобы облегчить отладку. И, если в дебаге произойдет порча памяти, то ее можно отловить. Visual Studio выдает в таком случае окно с сообщением и пишет в Output что-то вроде


Heap corruption at address.
HEAP[MyProg.exe]: Heap block at 0AC6A400 modified at 0AC6A6EC
past requested size of 2e4

Итак, в чем состоят отличия и каким образом отлавливаются ошибки. Давайте я пример приведу, с примером удобнее.

class CBase 
{
public:
int BaseI;
int BaseJ;
};

class CDerived : public CBase
{
public:
int DerivedI;
};

int main()
{
CBase *pBase = new CBase;//(1)

pBase->BaseI = 3;
pBase->BaseJ = 4;//(2)

delete pBase;//(3)

return 0;
}

Как будет выглядеть память в точке (1). (Чтобы вывести окно с памятью, выберите Debug->Windows->Memory->Memory1).

0x00984ED8  cd cd cd cd cd cd cd cd fd fd fd fd 00 00 00 00

У меня экземпляр класса CBase расположился по адресу 0x00984ED8. Оба int’а, а это восемь байт, заполнены значением 0xCD, Clean Memory. Это значение по умолчанию.
Дальше четыре байта 0XFD, Fence Memory, она же «no mans land». Это такой заборчик, которым обрамляется свежевыделенная память. Перед адресом 0x00984ED8 стоят точно такие же четыре байта.

Точка (2).

0x00984ED8  03 00 00 00 04 00 00 00 fd fd fd fd 00 00 00 00

Мы записали значения 3 и 4 и они идут одно за другим. Младший байт идет первым, потому что я работают с little endian платформой.

Точка (3)

0x00984ED8  dd dd dd dd dd dd dd dd dd dd dd dd 00 00 00 00

Память после удаления заполняется значениями 0xDD, Dead Memory. После вызова функции HeapFree() будет заполнена значениями 0xFEEEFEEE.

Давайте теперь сымитируем багу и посмотрим как Visual Studio ее поймает. Это реальная бага, я ее упростила до синтетического примера. На самом деле кода было больше и он был размазан по нескольким функциям.


CBase *pBase = new CBase;//(1)

pBase->BaseI = 3;
pBase->BaseJ = 4;//(2)

CDerived* pDerived = static_cast<CDerived*>(pBase);

pDerived->DerivedI = 7;//(3)
delete pBase;

Итак, мы стали приводить по иерархии с помощью static_cast’а, вместо dynamic_cast’а. Что в итоге получили. В точках (1) и (2) программа выглядит все также. В точке (3) мы полезли в чужую память и затерли забор.

03 00 00 00 04 00 00 00 07 00 00 00 00 00 00 00

После попытки вызвать delete pBase мы получим сообщение об ошибке, потому что забора нет, а это означает, что мы лазили в чужую память.

HEAP CORRUPTION DETECTED: after Normal block (#68) at 0x008D4ED8.
CRT detected that the application wrote to memory after end of heap buffer.

Еще различия между дебажной и релизной кучами приводят к тому, что программа начинает себя вести по-разному в дебаге и в релизе. Простой пример — дебажная «падает», релизная нет. Очень может быть, что «падение» — это не падение вовсе, а как раз сообщение о порче памяти. Почитайте повнимательнее, что там в окне написано.
Также народ жалуется, что дебажная версия работает сильно меденнее релизной. Причиной этого в том числе может быть дебажная куча. В интернетах пишут, что можно ее в дебаге отключить то ли с помощью переменной окружения _NO_DEBUG_HEAP, то ли NO_DEBUG_HEAP, в единицу ее надо выставить. Я пробовала ее отключить, куча осталась дебажной.

Ссылки по теме:
Win32 Debug CRT Heap Internals
Inside CRT: Debug Heap Management
Memory Management and the Debug Heap (MSDN)
Приведение типов в C++

Эта программа о времени пузырьковой сортировки, вставки и сортировки.

Я запустил свою программу и получил ошибку отладки,

HEAP CORRUPTION DETECTED:after Normal block(#152)at 0x006613C0 CRT Detected

чтобы приложение записывало в память после завершения буфера кучи.

Затем я удаляю последние 3 строки кода (delete [] a; delete [] b; delete [] c) в void part_1(int n) чтобы это работало. И мой профессор сказал мне: «Ваша программа должна иметь другие ошибки, эти ошибки вызывают
ошибки в операторах удаления. «и я не должен удалять последние 3 строки кода. Я не могу найти его. Пожалуйста, помогите.

// Part-1 : --------------------------- sorting algorithms

void bubbleSort(double *x, int n)
{
// Implement the sorting function using the bubble sort algorithm.
double temp;
for (int j = 0;j < n;j++) {
for (int i = 0;i < n;i++) {
if (x[i] > x[i + 1]) {
temp = x[i];
x[i + 1] = x[i];
x[i + 1] = temp;
}
}
}
}void insertionSort(double *x, int n)
{
// Implement the sorting function using the insertion sort algorithm.

for (int i = 1;i < n;i++) {
double temp = x[i];
int j = 0;
for (j = i - 1;j >= 0 && x[j]>temp;j--) {
x[j + 1] = x[j];
}
x[j + 1] = temp;
}

}int compare_1(const void *a, const void *b) {
double *X = (double *)a;
double *Y = (double *)b;
if (*X > *Y) {
return 1;
}
else if (*X < *Y)
return -1;
return 0;

}

void part_1(int n)
{
srand((unsigned)time(NULL));  // set the seed of the random number generator

double *a = new double[n];  // create 3 arrays with identical contents
double *b = new double[n];
double *c = new double[n];

for (int i = 0; i < n; i++)
a[i] = b[i] = c[i] = rand() / 10000.0;

clock_t begin, end;
double elapsedTime;

cout << "Bubble sort: sorting an array of size " << n << endl;
begin = clock();
bubbleSort(a, n);
end = clock();

elapsedTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "Elapsed time = " << elapsedTime << " seconds" << endl << endl;

for (int i = 0; i < n - 1; i++)
if (a[i] > a[i + 1])
{
cout << "Bubble sort : Incorrect resultsnn";
break;
}

cout << "Insertion sort: sorting an array of size " << n << endl;
begin = clock();
insertionSort(b, n);
end = clock();

elapsedTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "Elapsed time = " << elapsedTime << " seconds" << endl << endl;

for (int i = 0; i < n - 1; i++)
if (b[i] > b[i + 1])
{
cout << "Insertion sort : Incorrect resultsnn";
break;
}

cout << "Write your statements to sort array c[] using qsort()n";
cout << "qsort: sorting an array of size " << n << endl;

begin = clock();

// #### write your statements to sort array c[] using qsort().
//      Define your own compare function.
qsort(c, n, sizeof(double), compare_1);

end = clock();

elapsedTime = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "Elapsed time = " << elapsedTime << " seconds" << endl << endl;

for (int i = 0; i < n - 1; i++)
if (c[i] > c[i + 1])
{
cout << "qsort : Incorrect resultsnn";
break;
}
delete[] a;
delete[] b;
delete[] c;
}
int main()
{
part_1(50000);

system("pause");
return 0;
}

-1

Решение

Эта ошибка возникает из-за повреждения памяти. Повреждение памяти произошло из-за того, что вы записали за предел массива.
Например: если есть массив из 5 целых чисел, например

int array[5];

Вы не должны делать такие вещи, как

int n=4;
array[n+1] = 10; //array out of bound memory write operation

C / C ++ не проверяет массив вне связанной операции. Это разрешает такую ​​операцию без ошибки компиляции. В результате, когда вы запускаете программу, может произойти все что угодно. Поэтому ответственность за проверку таких ошибок лежит на программисте.

Один такой экземпляр найден в вашем коде.

void bubbleSort(double *x, int n)
{
// Implement the sorting function using the bubble sort algorithm.
double temp;
for (int j = 0;j < n;j++) {
for (int i = 0;i < n;i++) {
if (x[i] > x[i + 1]) {
temp = x[i];
x[i + 1] = x[i]; // out of bound write when i=n-1.
x[i + 1] = temp;
}
}
}
}

0

Другие решения

В bubbleSort Ваш индекс массива выходит за пределы диапазона. Измените функцию, как показано ниже, и вы увидите, что происходит:

void bubbleSort(double *x, int n)
{
// Implement the sorting function using the bubble sort algorithm.
double temp;
for (int j = 0; j < n; j++) {
for (int i = 0; i < n; i++) {
if (i + 1 >= n)
{ // index is out of range
cout << "Bummern";
exit(1);
}
if (x[i] > x[i + 1]) {
temp = x[i];
x[i + 1] = x[i];
x[i + 1] = temp;
}
}
}
}

Там, скорее всего, аналогичные проблемы в других ваших функций сортировки.

0

  • Ошибка headlight leveling авенсис
  • Ошибка headlamp failure service requ 104
  • Ошибка hds ленд ровер
  • Ошибка hds range rover не заводится
  • Ошибка hdmi нет сигнала