2009-11-17 2 views
5

Я получаю странный результат в следующем C-коде.malloc() и память кучи

int main() 
{ 
    int *p = (int *) malloc(100); 
    p[120] = 5; 
    printf("\n %d", p[120]); 
} 

Поскольку я выделил всего 100 байт, этот код должен вызвать ошибку сегментации. Однако он печатает «5» и не дает никакой ошибки времени выполнения. Может кто-нибудь объяснить причину?

+4

Наверное, просто повезло. –

+5

Вы написали 5 к месту, которое не принадлежало вам. Если владельцу этого места не понравилось то, что вы сделали с его домом, он отомстит. ** Опасайтесь **, он может принадлежать вашему USB-дисководу, и он отформатирует следующий диск, который вы вставляете. – pmg

+4

@pmg: Реально, это не очень вероятно в современной операционной системе с защищенным режимом. – bcat

ответ

20

Нет, код не должен (обязательно) давать segfault. При попытке доступа к странице виртуальной памяти, которая не выделена для вашего процесса, возникает segfault.

«Куча» или «свободный магазин» - это область виртуальных страниц памяти, принадлежащая вашему процессу. API malloc() подразделяет эту область на блоки и возвращает указатель на блок.

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

Для получения дополнительной информации о куче коррупции и способах обнаружения его в отладочной версии коды, это отличная книга:

Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire alt text http://ecx.images-amazon.com/images/I/5148TK6JCVL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg

Дополнения для педантичного: В редких случаях , путем доступа к памяти за пределами кучи блока, вы можете получить доступ к памяти, которая не является частью кучи. В этих случаях вы можете получить ошибку сегментации, которую вы ожидали. Вы также можете испортить некоторую другую структуру данных, чем кучу. Это действительно случайность. Однако сама куча очень велика по сравнению с типичными блоками кучи, поэтому 99% временного кода, такого как ваш пример, испортит кучу. Пример, который вы предоставляете, относится к этому 99% -му делу.

+0

На самом деле, поскольку он попросил изменить 20 байтов за конец стека, в зависимости от архитектуры и окружающего кода он мог вместо этого наложить стек или даже сам изменить программу. Поведение действительно не определено. –

+2

T.E.D. Это всего лишь «своего рода». Он, без сомнения, использует машину с размером страницы виртуальной памяти. Предположительно исполняемый код имеет разную защиту VM, чем куча. Я бы сказал, что он работает в такой системе, потому что существует стандартная функция библиотеки malloc(). То, что вы пишете, правда, однако, в частности, на Radio Shack Model III работает TRS-DOS на Z-80. ;) –

+0

И да, даже в системе страниц VM, то, что вы пишете, может случиться. Это не так уж и маловероятно, и это не очень педагогично, чтобы идти на эту деталь, что редко имеет значение. Решите проблему на том уровне, на котором она указана. Избегайте педантизма. –

0

Вы пишете в память, которую вы не выделили. В конечном итоге программа может закончиться из-за эффектов кучи, если время ее выполнения достаточно велико.

6

Недопустимые обращения к памяти не всегда будут причиной сбоев сегментации, ошибки шины или другого сбоя. Например, если есть еще один блок, выделенный сразу после вашего массива, вы меняете значения в , что блок - это может быть что угодно.

0

Вы пишете в неинициализированную память; это разрешено в C, это просто не очень хорошая идея. Подобная вещь не обязательно должна приводить к ошибке сегментации.

+2

Ваше использование слова «разрешено» вводит в заблуждение. Он синтаксически действителен, но вызывает неопределенное поведение. –

3

Нет, это может дать segfault, но только если память вне вашего процесса. В противном случае он просто изменит другую область вашей программной памяти. C не проверяет это или защищает вас каким-либо образом, даже в очевидных случаях, подобных приведенному выше. Многие многие программные крекеры используют эту «функцию» для C, чтобы переписать программу с повышенными привилегиями и дать контроль над вашей машиной. Он называется buffer overflow exploit.

Вот почему C (и C++) следует действительно избегать для нового программного обеспечения, предпочитая более безопасные языки, такие как Ada.

+1

Я знаю, что последнее предложение получило бы отрицательный результат. Мне все равно. Это правда. –

+0

+1 от меня. Я полностью согласен. – lesscode

0

Общие причины ошибки сегментации:

  • разыменования указателя с недопустимым значением
  • разыменования нулевые указатели
  • пытается записать в только для чтения сегмента
  • свободно ИНГ неправильные указатели или ип .

    int * x = 0;

    x = 200;/Сегментация причины неисправности */

ошибку сегментации генерируются исключения MMU на основании того, что определяется как незаконный доступ к памяти. В зависимости от того, как ОС структурирует свою память, один доступ к памяти на ОС может быть законным (хотя и неправильным), а на другой ОС он может быть незаконным.

+0

Это лето, но ... x = 200 в порядке, * x = 200 ведет к segfault. –

Смежные вопросы