Повреждение кучи после освобождения памяти в C - PullRequest
0 голосов
/ 09 ноября 2019

У меня есть следующий фрагмент кода:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef _WIN32
    #include <windows.h>
#elif defined __unix__
    #include <unistd.h>
#endif

#define BENCH

#ifndef BENCH
    #define N 10000
#endif

int main(void)
{
#ifdef BENCH
    FILE* output = fopen("out.csv", "w");
    for (int N = 10000; N <= 100000; N += 10000)
#endif
    {
        int* a = malloc(N * sizeof(int));
        if (a == NULL)
            abort();

        for (int i = 2; i < N; i++)
            a[i] = 1;

#ifdef BENCH
        clock_t begin = clock();
#endif

        for (int i = 2; i < N; i++)
        {
            if (a[i])
            {
               #if defined (BENCH) && defined (_WIN32)
                    Sleep(1);
               #elif defined (BENCH) && defined (__unix__)
                    sleep(0.001);
               #endif
               for (int j = i; j <= N / i; j++)
                    a[i * j] = 0;
            }

        }

#ifdef BENCH
        clock_t end = clock();
        double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
        fprintf(output, "%d,%f\n",N ,time_spent);
        free(a); //This is where the corruption occurs
#else
        for (int i = 2; i < N; i++)
        {
            if (a[i])
                printf("%9d ", i);
        }
        puts("");
#endif
    }
#ifdef BENCH
    fclose(output);
#endif
}

Если BENCH не определено, программа принимает предопределенное N и отображает результаты на консоли. Производительность алгоритма не измеряется.

, если определено BENCH, с помощью цикла for создается несколько экземпляров проблемы с различным размером ввода (N). Как только один экземпляр проблемы заканчивается, производительность алгоритма записывается в файл output.csv. Затем память, выделенная для массива этого экземпляра, должна быть освобождена.

Именно здесь происходит повреждение кучи, по крайней мере, в соответствии с тем, что говорит компилятор Microsoft Visual C ++ в Visual Studio 2019. Кто-нибудь знает, почему это происходит? И malloc(), и free() мне кажутся правильными. Программа работает просто отлично, если free() удалено.

1 Ответ

0 голосов
/ 09 ноября 2019

Проблема, наконец, была обнаружена в условии завершения цикла for (int j = i; j <= N / i; j++), а не в free(). Изменение на for (int j = i; j < N / i; j++) решило проблему повреждения кучи.

Как и Какой-то программист чувак указал в комментариях, исключение Out Of Bounds происходило без уведомления отладчика. Находясь в Visual Studio, где я в основном пишу код на C #, у меня была иллюзия, что, если что-то пойдет не так, я, по крайней мере, получу исключение в строке, где могут произойти плохие вещи.

Это не случай, так как C не имеет никакой проверки границ. Неопределенное поведение имеет тенденцию работать "хорошо" в некоторых случаях, тогда что-то незначительное изменяется, когда все ломается. Как указал AbbysSoul , повреждение кучи происходило во всех случаях, даже если BENCH не определено. Когда критическая операция, такая как free(), была вызвана в поврежденной куче, процесс был обречен на крах.

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

...