Страницы

Поиск по вопросам

среда, 4 декабря 2019 г.

Может ли `free` отработать с ошибкой

#c


Допустим есть кусок кода:

char *ptr = (char*)malloc(needed_size);
if (!ptr) {
   error_handling();
} else {
   do_something_without_freeing_ptr();
   free(ptr);
   ptr = 0;
}


Может ли вызов free не отработать/отработать неправильно и к каким последствиям это
может привести?



Подразумевается, что между вызовом malloc и free выделенная память не освобождается,
значение указателя не изменяется.

Не лучше ли, во избежание случайного изменения значения ptr, писать:

char * const ptr = malloc(needed_size);


Это не избавит от возможности написать free(ptr); free(ptr);, но по крайней мере
убережет от чего-то типа ptr = NULL;
    


Ответы

Ответ 1



free определена как функция, не возвращающая значений, т.е. возможности вернуть ошибку у неё нет. Если ей передать указатель полученный не от calloc, malloc, realloc, либо вызвать повторно для одного и того же указателя или изменить байты за пределами запрошенного массива, действия зависят от реализации. Обычно это приводит к непредсказуемым ошибкам в программе, возможно в совершенно другом месте. Такие ошибки трудно локализовать. К примеру, в начале выделенного куска памяти перед тем, на что указывает указатель, обычно находится заголовок — структура с информацией об этом куске и о следующем. Кроме этого, где-то может быть информация о свободных кусках. Если, например, в результате функции gets() будет испорчен заголовок для следующего блока, то проявиться эта ошибка может даже не когда этот блок будет выделен malloc, а когда этот блок будет освобождаться. Есть библиотеки реализующие набор функций calloc, malloc, realloc, free с дополнительными средствами обнаружения их ошибочного использования. Написать char * const ptr = malloc(needed_size); можно, но это не гарантирует, что вы не скопируете указатель в другую переменную или примените индекс за пределами [0; needed_size[.

Ответ 2



Согласно Стандарту C11 (7.22.3.3/2): The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined. Т.о. если память была корректно выделена и не была после этого ещё освобождена с помощью free или realloc, всё должно быть хорошо. Если провести некоторую параллель с c++, то необходимость отсутствия ошибок в функции free чем-то сродни необходимости не бросать исключения в деструкторах. На счет дополнительного const к указателю - идея хорошая и правильная. Позволяет выявлять ситуации непреднамеренной модификации или повторного использования переменной в разных контекстах. Главное здесь, не переборщить и не завалить код constами там, где от этого совсем нет профита. С другой стороны, невозможность изменить значение указателя на NULL будет препятствовать защите от повторного освобождения. Т.к. если указатель мутабельный, можно писать так и не бояться последствий: T* ptr = malloc(/*...*/); // ... free(ptr); ptr = NULL; free(ptr); // Безопасно Понятно, что для T* const ptr такое будет невозможно.

Ответ 3



Насколько мне известно, стандартный С не позволяет контролировать неконсистентный heap и вообще какие-либо ошибки при освобождении памяти. Поэтому нужно пользоваться или возможностями используемой операционной системы, как GetProcessHeap, HeapAlloc, HeapFree, HeapValidate под Windows или расширениями используемого компилятора, см. здесь и здесь.

Комментариев нет:

Отправить комментарий