2012-03-09 2 views
4

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

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

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

ответ

2

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

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

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

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


Кроме того, это лучше not to cast the result of malloc - see this answer

1

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

1

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

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

1

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

1

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

2

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

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

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