Почему calloc выделяет 1 байт, если nelem или elsize == ноль? - PullRequest
2 голосов
/ 18 октября 2019

Я работаю над разработкой отладочных реализаций четырех основных процедур выделения памяти malloc, realloc, calloc и free (аналогичных по работе с Electric Fence) для отладки повреждения кучи на встроенных системах, которые делаютне имеют ресурсов для запуска других инструментов отладки памяти или для которых не существует других инструментов (например, LynxOS 7.0 для PowerPC поставляется с GCC 4.6.3 и запатентованной реализацией glibc и libstdc ++, которая не включает mtraceсемейство функций).

Ниже приведен исходный код calloc из calloc.c из библиотеки GCC.

PTR
calloc (size_t nelem, size_t elsize)
{
  register PTR ptr;  

  if (nelem == 0 || elsize == 0)
    nelem = elsize = 1;

  ptr = malloc (nelem * elsize);
  if (ptr) bzero (ptr, nelem * elsize);

  return ptr;
}

Почему nelem и elsize оба установлены равными1 если либо равно 0?

Если я попытаюсь выделить 0 чанков размером n или n чанков с размером 0, то в любом случае это не приведет к агрегированиювыделение 0 всего байтов, а не 1 байтов?

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Почему calloc выделяет 1 байт, если nelem или elsize == ноль?

Для уменьшения неоднозначности.

calloc(0, x), calloc(x, 0), malloc(0), в случае успеха может вернуть NULL или не NULL указатель. В обоих случаях указатель не может быть отменен без указания неопределенного поведения (UB).

В случае неудачи возвращается указатель NULL.

Byпри условии, что размер выделения больше 0, неопределенность при возврате NULL отсутствует - выделение не удалось из this calloc().


Обратите внимание, что лучшая функция будеттакже обнаружить переполнение продукта.

if (nelem == 0 || elsize == 0) {
  nelem = elsize = 1;
} else if (SIZE_MAX/nelem > elsize) {
  return NULL;  // Too much for this implementation
}
...

Дальнейшие размышления о Electric_Fence :

Я бы ожидал, что malloc(0) этого проекта также обеспечит 0байты не выделены. Тем не менее, простой вызов ptr = malloc (0); if (ptr) bzero (ptr, 0); не приведет к обнулению распределения в 1 байт. if (nelem == 0 || elsize == 0) nelem = elsize = 1; гарантирует, что выделение составляет не менее 1 байта и , что выделение обнуляется.

1 голос
/ 18 октября 2019

Да, это просто плохой код, который не является неожиданным из libiberty / gnulib / etc. Насколько я понимаю, они уже заменяют malloc, если malloc(0) возвращает нулевой указатель, а не уникальный указатель для каждого вызова, поэтому я не вижу веской причины для того, чтобы calloc передавал 1 в malloc вместо 0Более того, передача 1 разрывов / подрывает инструменты отладки, такие как дезинфицирующие средства, которые могут сообщить вам, если вы случайно разыменовали указатель на «массив с нулевым элементом».

Код также невероятно опасен, поскольку он не проверяетпереполнение умножения;для этого требуется любая правильная реализация calloc.

TL; DR: этот код является ненужным.

...