Подтвердить что ты не робот

Как обнаружить сбой malloc?

Каков переносимый способ проверить, не удалось ли malloc выделить ненулевой блок памяти?

4b9b3361

Ответ 1

В соответствии с Single Unix Specification, malloc вернет NULL и установит errno, когда он сработает.

Ответ 2

Я всегда делаю это:

tok = malloc( sizeof( char ) * ( strlen(tc) + 1 ) );

if( tok == NULL )
{
     /* Malloc failed, deal with it */
}

Некоторые люди делают tok = (type) malloc( ... ), но вы должны использовать результат, потому что, по-видимому, он покрывает некоторые неприятные ошибки. Я сделаю некоторые исследования и посмотрю, смогу ли я узнать, что они собой представляют.

Edit:

Кастинг malloc может скрыть отсутствующий #include <stdlib.h>

Я нашел эту ссылку, которая содержала очень хорошее объяснение:

http://cboard.cprogramming.com/faq-board/25799-faq-casting-malloc.html

"Итак, когда вы говорите это (char *) malloc (10)

Вы говорите, что принимаете все malloc возвращает, преобразует его в char *, и присваиваем это переменной в вопрос.

Это хорошо и хорошо, если malloc прототип правильно (путем включения stdlib.h), где он определяется как return void *.

Проблема возникает, когда вы не можете include stdlib.h, а компилятор изначально предполагает, что malloc возвращает int. Реальная проблема заключается в том, что вы НЕ ДОЛЖНЫ получить предупреждение от компилятора.

Вы весело конвертируете этот int в char * (через литой). На машинах где sizeof (char *) отличается от sizeof (int), код серьезно сломан.

Теперь, если у вас есть только char * var = malloc (10); И вы пропускаете включите, вы получите предупреждение от компилятора."

Ответ 3

Конечно. Портативный способ - проверить, возвращается ли malloc(...) NULL.

Ответ 4

Вы можете обнаружить сбой, если:

malloc(n) возвращает NULL

Это самый распространенный и надежный тест для обнаружения отказа распределения. Если вы хотите быть переносимым за пределы POSIX/SUS, я бы не стал доверять errno. Если вам нужны детали, скажем, для ведения журнала, я должен был бы обнулить errno перед вызовом, посмотреть, изменилось ли оно, а затем, возможно, зарегистрировать это.

malloc(n) возвращает не адрес NULL, который не поддерживается фактической памятью

Прикоснитесь к нему и посмотрите, не убили ли вы ОС. Да, это может произойти. Он называл overcommit памяти и напоминает дробный резервный банк. Это оптимистичный подход к ОС или гипервизору для возврата адресов в виртуальную память, которую они играют в азартные игры, которые им никогда не понадобится. Это происходит на Linux, VMware. (Я не могу найти никаких явных доказательств чрезмерной обработки Windows, хотя запрошенные страницы только "зафиксированы" , когда они коснулись.)

Тогда возникает вопрос: "Как я уверенно обнаруживаю, что моя программа вот-вот потерпит крах при доступе к адресу, который я получил от malloc, которому я ранее доверял, как подростковая подача?". Одним из способов может быть read() случайный файл в тестовой области и посмотреть, вернет ли ОС EINVAL или эквивалент.

Для дополнительных очков

malloc(0) возвращает NULL и оставляет errno undefined

Я знаю, что вопрос задан для "ненулевого [размера] блока памяти", но это интересно. Рассмотрим SUS-совместимый распределитель, который намеревается вернуть не NULL для распределения нулевого размера (он может это сделать), но затем он терпит неудачу, поэтому он должен вернуть NULL. И он может попытаться установить errno. Это провал? Я думаю, что Хоар говорит, что мы заплатили миллиард долларов за эту двусмысленность. Таким образом, вызов malloc(0) не переносится, и, вероятно, этот вопросник знал об этом!

Ответ 5

malloc(n) возвращает NULL при ошибке.
malloc(0) может возвращать NULL.

Чтобы обнаружить отказ:

void ptr = malloc(n);
if (ptr == NULL && n > 0) Handle_Failure();

Примечания:

Как и в случае OP: "... выделить ненулевой блок памяти", часто код таков, что запрос на размещение 0 не может быть выполнен, поэтому тест 0 не нужен.

size_t nstr = strlen(some_string) + 1;
void ptrstr = malloc(nstr);
if (ptrstr == NULL) Handle_Failure();

Некоторые системы устанавливают errno при сбое, но не все. Установка errno из-за сбоя выделения памяти не указана в спецификации C11.

malloc(n) ожидает, что n будет неподписанным типом size_t. Использование int n с отрицательным значением, безусловно, преобразуется в какое-то большое значение без знака, а затем, скорее всего, не удастся выделить память.