Сбой realloc после нескольких вызовов только тогда, когда не происходит отладка

Приведенный ниже код иногда дает сбой на buffer = (char*) realloc(buffer, allocated * sizeof(char)); вызов (отмечен ниже), который я использую для динамического выделения пространства для char*Изначально выделяя 1 символ и удваивая выделенное количество каждый раз, когда у меня уже есть память, недостаточная для хранения строки.

У меня очень похожий код во многих других частях моего проекта, с той же политикой выделения памяти и вызовами (меняются только типы void* Я перехожу к realloc).

Я использую VS2010 для отладки проблемы, и когда я запускаю программу в режиме отладки, функция всегда завершается успешно.

Однако при вызове программы из командной строки существует высокая вероятность того, что через некоторое время один из вызовов realloc завершится с ошибкой "Место чтения нарушения доступа" - хотя это происходит не всегда и только происходит после того, как приведенная ниже функция была вызвана несколько раз, причем многие перераспределения уже произошли.

Что еще более странно, я поместил несколько отпечатков до и после вызова realloc, чтобы подтвердить, изменилось ли расположение указателя, и, когда я сделал это и запустил программу, вызовы realloc перестали произвольно прерываться.

Что я делаю неправильно?

TOKEN
next_token_file(FILE* file, 
                STATE_MACHINE* sm, 
                STATE_MACHINE* wsssm)
{
    char* buffer = (char*) malloc(sizeof(char));
    size_t allocated = 1;
    size_t i = 0;
    while(1)
    {
    /*
    ... code that increments i by one and messes with sm a bit. Does nothing to the buffer.
    */
        // XXX: This fails when using realloc. Why?
        if(i + 1 >= allocated)
        {
            allocated = allocated << 1;
            buffer = (char*) realloc(buffer, allocated * sizeof(char));
        }
        buffer[i] = sm->current_state->state;
    /*
    ... more code that doesn't concern the buffer
    */
    }
    // Null-terminate string.
    buffer[++i] = 0;
    TOKEN t = {ret, buffer};
    return t;
}

3 ответа

Решение

Благодаря этим линиям

char* buffer = (char*) malloc(16 * sizeof(char));
size_t allocated = 1;

программа сокращается buffer для первых 4 перераспределений. Таким образом, программа пишет в нераспределенную память из i=16 на, что является неопределенным поведением, поэтому может произойти все что угодно. Также это, скорее всего, разрушает управление памятью, которое, в свою очередь, делает realloc() потерпеть поражение.

Вы можете изменить эти две строки на:

size_t allocated = 16; /* or = 1 if the 16 was a typo. */
char * buffer = malloc(allocated); 

Другие заметки:

Ссылаясь на последнее примечание, следующие изменения должны быть применены

char * buffer = malloc(allocated); 

может стать:

char * buffer = malloc(allocated); 
if (NULL == buffer)
{
  /* Error handling goes here. */
}

а также

buffer = (char*) realloc(buffer, allocated * sizeof(char));

может стать:

{
  char * pctmp = realloc(buffer, allocated);
  if (NULL == pctmp)
  {
    /* Error handling goes here. */
  }
  else
  {
    buffer = pctmp;
  }
}

Больше комментариев, чем ответа, но у меня нет 50 пунктов, чтобы комментировать.

Это:

char* buffer = (char*) malloc(16 * sizeof(char));

должно быть

char* buffer = (char*) malloc(1 * sizeof(char));

или же

allocated = 16.

Я не знаю, когда вы увеличиваете или уменьшаете i. Но я бы поспорил, что, согласно этому фрагменту, ваша проблема заключается в том, что вы перераспределяете бесконечно, и поскольку вы не проверяете realloc, возвращает NULL, что приведет к сбою вашей программы;)

Как уже было сказано, даже не очень хорошо работающие pritf-ы это подтверждают, а вы нарушаете блок памяти. это произойдет, если переопределить адрес памяти, который был перезаписан за пределами диапазона (в любом случае, за исключением его UB).

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

Другие вопросы по тегам