Как обнаружить сбой malloc? - PullRequest
26 голосов
/ 13 июня 2011

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

Ответы [ 5 ]

32 голосов
/ 13 июня 2011

В соответствии с Single Unix Спецификацией , malloc вернет NULL и установит errno при сбое.

15 голосов
/ 13 июня 2011

Я всегда так делаю:

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

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

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

Редактировать:

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

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

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

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

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

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

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

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

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

6 голосов
/ 07 октября 2014

Ошибка может быть обнаружена, когда:

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

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

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

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

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

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

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

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

6 голосов
/ 13 июня 2011

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

2 голосов
/ 07 октября 2014

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 с отрицательным значением, безусловно, приведет к некоторому большому значению без знака, а затем, скорее всего, приведет к ошибке выделения памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...