Запись в указатель вне границ после malloc () не вызывает ошибку - PullRequest
6 голосов
/ 26 декабря 2010

, когда я пытаюсь код ниже, он работает нормально.Я что-то упустил?

main()
{
    int *p;
    p=malloc(sizeof(int));
    printf("size of p=%d\n",sizeof(p));
    p[500]=999999;
    printf("p[0]=%d",p[500]);
    return 0;
}

Я пробовал это с помощью malloc (0 * sizeof (int)) или чего-то еще, но это работает просто отлично.Программа падает только тогда, когда я вообще не использую malloc.Таким образом, даже если я выделю 0 памяти для массива p, он все равно будет правильно хранить значения.Так почему же тогда я беспокоюсь о malloc?

Ответы [ 7 ]

15 голосов
/ 26 декабря 2010

Может показаться нормально работающим , но это совсем не безопасно.Записывая данные за пределы выделенного блока памяти, вы перезаписываете некоторые данные, которые не следует делать.Это одна из самых серьезных причин ошибок в работе сегмента и других ошибок памяти, и то, что вы наблюдаете, когда вы работаете в этой короткой программе, так затрудняет поиск основной причины.

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

Valgrind является отличным инструментом для анализа ошибок памяти, таких как та, которую вы предоставляете.

@ Дэвид сделал хороший комментарий.Сравните результаты выполнения вашего кода с выполнением следующего кода .Обратите внимание, что последнее приводит к ошибке во время выполнения (практически без полезного вывода!) На ideone.com (переход по ссылкам), тогда как первый завершается успешно, как вы видели.

main()
{
    int *p;
    p=malloc(sizeof(int));
    printf("size of p=%d\n",sizeof(p));
    p[500]=999999;
    printf("p[0]=%d",p[500]);
    p[500000]=42;
    printf("p[0]=%d",p[500000]);
    return 0;
}
13 голосов
/ 26 декабря 2010

Если вы не выделяете память, в p содержится мусор, поэтому запись в нее, скорее всего, не удастся.После того, как вы сделали правильный вызов malloc, p указывает на правильное местоположение в памяти, и вы можете записать в него.Вы переписываете память, в которую не должны писать, но никто не собирается держать вас за руку и рассказывать об этом.Если вы запустите свою программу и отладчик памяти, такой как valgrind, он скажет вам.Добро пожаловать в C.

9 голосов
/ 26 декабря 2010

Запись за пределы вашей памяти - это «Неопределенное поведение», что означает, что может произойти все что угодно, включая вашу программу, работающую так, как будто то, что вы только что сделали, было совершенно законно. Причина, по которой ваша программа работает так, как будто вы сделали malloc(501*sizeof(int)), полностью зависит от реализации и может действительно относиться ко всему, включая фазу луны.

2 голосов
/ 26 декабря 2010

Это потому, что P будет назначен некоторый адрес независимо от того, какой размер вы используете с malloc (). Хотя при нулевом размере вы бы ссылались на недопустимую память, поскольку память не была выделена, но она может находиться в месте, которое не вызовет сбой программы, хотя поведение будет неопределенным.

Теперь, если вы не используете malloc (), он будет указывать на расположение для мусора и пытаться получить доступ, который может вызвать сбой программы.

1 голос
/ 27 декабря 2010

Когда вы вызываете malloc (), для вас выделяется небольшой фрагмент памяти из большей страницы.

    malloc(sizeof(int));

На самом деле не выделяет 4 байта на 32-битной машине (распределитель увеличивает его доминимальный размер) + размер метаданных кучи, используемых для отслеживания фрагмента в течение его времени жизни (фрагменты помещаются в ячейки в зависимости от их размера и помечаются как используемые или освобождаемые распределителем).hxxp: //en.wikipedia.org/wiki/Malloc или, более конкретно, hxxp: //en.wikipedia.org/wiki/Malloc#dlmalloc_and_its_derivatives, если вы тестируете это в Linux.

Поэтому пишите не толькограницы вашего куска не обязательно означают, что вы собираетесь потерпеть крах.При p + 5000 вы не пишете за пределами страницы, выделенной для этого начального блока, поэтому вы технически пишете на действительный сопоставленный адрес.Добро пожаловать к повреждению памяти.http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=heap+overflows

1 голос
/ 26 декабря 2010

Я пробовал это с malloc (0 * sizeof (int))

Согласно C99, если размер, переданный malloc, равен 0, среда выполнения C может вернуть либо NULLуказатель или распределение ведет себя так, как если бы запрос был для ненулевого распределения, за исключением того, что возвращенный указатель не должен быть разыменован.Таким образом, это определяется реализацией (например, некоторые реализации возвращают буфер нулевой длины), и в вашем случае вы не получите указатель NULL обратно, но вы используете указатель, который не следует использовать. Если вы попробуете его в другой среде выполнения, вымог получить нулевой указатель обратно.

0 голосов
/ 09 июля 2011

Наш CheckPointer инструмент может обнаружить эту ошибку.Он знает, что распределение p было выделено фрагменту из 4 байтов, и, таким образом, назначение сделано, оно находится вне области, для которой было выделено p.Он скажет вам, что присвоение p [500] неверно.

...