Доступ за пределами выделенного пространства в C - PullRequest
4 голосов
/ 09 марта 2012

Ну, я всегда думаю, что если я вызываю функцию malloc, я назначаю определенный объем памяти, но я только что понял, что если я напишу:

int* a = (int*)malloc(sizeof(int) * 2);

Я могу присвоить значение a[4] или любому другому индексу, хотя я в этом случае могу назначить только a[0] или a[1]. Какая у меня ошибка в концепции?

Ответы [ 6 ]

2 голосов
/ 09 марта 2012

В C нет способа проверить переполнение массива.Вы можете продолжать запись за пределы массива, пока не включите запись по недействительному адресу или странице только для чтения и т. Д.

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

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

2 голосов
/ 09 марта 2012

Когда вы пишете a[4], это то же самое, что и запись *(a + 4).Поскольку компилятор не знает, сколько памяти выделено по адресу, на который указывает a, он с радостью позволит вам обратиться к памяти.

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

Вы правы в том, что можете толькоприсвойте a[0] или a[1] безопасно , но компилятор C позволит вам назначить за пределами этих границ (потому что он не знает ничего другого).

В вашем примере небезопасно делать a[4].


Кроме того, лучше не приводить результат malloc - см. Этот ответ

1 голос
/ 09 марта 2012

Чтобы расширить ответ Кейта: вы можете перезаписать память в куче, так как C не выполняет проверку границ во время компиляции или выполнения. a [x] в основном добавляет x * sizeof(x) к указателю "a". Указатель указывает на начало выделенного блока.

1 голос
/ 09 марта 2012

Неопределенное поведение - это просто неопределенное поведение. Может показаться, что это «работает», но это не так.

1 голос
/ 09 марта 2012

Причина, по которой вы можете сделать a[4], заключается в том, что C не выполняет проверку границ. Вы можете получить доступ к ячейке за пределами массива, и C сделает это.

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

1 голос
/ 09 марта 2012

Ошибка в концепции - это то, что С защитит вас!С считает, что вы знаете, что делаете.Вы действительно можете использовать только индекс 0 или 1, но это не остановит вас при использовании 4 (ну, может, операционная система).

...