malloc () и куча памяти - PullRequest
       22

malloc () и куча памяти

5 голосов
/ 17 ноября 2009

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

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

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

Ответы [ 6 ]

20 голосов
/ 17 ноября 2009

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

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

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

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

Написание твердого кода: методики Microsoft по разработке программ на C без ошибок, автор Steve Maguire alt text

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

6 голосов
/ 17 ноября 2009

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

3 голосов
/ 17 ноября 2009

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

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

0 голосов
/ 18 ноября 2009

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

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

    int * x = 0;

    х = 200; / вызывает ошибку сегментации * /

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

0 голосов
/ 17 ноября 2009

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

0 голосов
/ 17 ноября 2009

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

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