Связанный вопрос не совсем охватывает проблему переполнения буфера.
Deadalnix
1
потому что куча растет вверх.
Tylerl
2
Расположение памяти 0 вверху или внизу?
Ответы:
21
Я полагаю, что это происходит с самых первых дней вычислений, когда память была очень ограничена, и было неразумно предварительно выделять большой кусок памяти для монопольного использования стеком. Таким образом, выделяя кучу памяти от адреса с нуля вверх и стековую память от конца памяти вниз, вы можете иметь кучи и стек совместно в одной и той же области памяти.
Если вам нужно немного больше кучи, вы можете быть осторожны с использованием стека; если вам нужно больше стека, вы можете попытаться освободить кучу памяти. Результатом, конечно, были, в основном, впечатляющие сбои, поскольку стек иногда перезаписывал кучу, и наоборот.
В те времена не было никакого интервала, поэтому не было проблемы использования переполнения буфера. (Или, по крайней мере, в той мере, в которой существовал интервез, все это находилось в пределах объектов повышенной безопасности Министерства обороны США, поэтому не нужно было много думать о возможности злонамеренных данных.)
После этого для большинства архитектур это было вопросом поддержания совместимости с предыдущими версиями той же архитектуры. Вот почему перевернутые стеки все еще с нами сегодня.
Вернемся дальше в истории, и не было кучи, даже сегодня многие 8- и 16-битные микроконтроллеры не имеют кучи. Стек вырос, так что программа могла быть установлена по низкому адресу памяти, а стек был оставшейся памятью. Инициализация стека может быть выполнена перед загрузкой программы, упрощая программы.
Mattnz
1
У большинства маленьких микроконтроллеров есть куча, но не куча, которая растет. Трудно оправдать использование динамического выделения памяти в куче, когда у вас есть небольшой объем ОЗУ (<1 КБ) для работы. Обычно единственным изменяющимся размером раздела памяти является стек.
но переполнение буфера все еще может быть использовано, если стек пошел другим путем
взяв классику strcpyв качестве примера
foo(char* in){
char[100] buff;
strcpy(buff,in);
}
со стековой памятью как
ret foo
arg in
buff array
ret strcpy
buf pointer
in
это будет означать, что когда копирование завершено, адрес возврата для strcpyнаходится после буфера (вместо fooадреса возврата) и может быть перезаписан любым, что находится вin
В-третьих, стеки на процессорах Multics росли в положительном направлении, а не в отрицательном направлении. Это означало, что если бы вы на самом деле достигли переполнения буфера, вы бы перезаписывали неиспользуемые стековые фреймы, а не собственный указатель возврата, что значительно усложняло бы использование.
Это довольно интересное утверждение. Не стали ли переполнения буфера такой огромной проблемой только из-за «обычной» схемы процедуры вызова-стека-фрейма? Кроме того, сколько репутации Multics как полностью неуязвимого было просто случайностью аппаратного дизайна?
Что ж, отсутствие исполняемого стека (ов), вероятно, помогло Multics так же, как интеллектуальное направление стека, и, конечно же, во многих программах, написанных на PL / 1, переполнение строк также не было проблемой.
Ответы:
Я полагаю, что это происходит с самых первых дней вычислений, когда память была очень ограничена, и было неразумно предварительно выделять большой кусок памяти для монопольного использования стеком. Таким образом, выделяя кучу памяти от адреса с нуля вверх и стековую память от конца памяти вниз, вы можете иметь кучи и стек совместно в одной и той же области памяти.
Если вам нужно немного больше кучи, вы можете быть осторожны с использованием стека; если вам нужно больше стека, вы можете попытаться освободить кучу памяти. Результатом, конечно, были, в основном, впечатляющие сбои, поскольку стек иногда перезаписывал кучу, и наоборот.
В те времена не было никакого интервала, поэтому не было проблемы использования переполнения буфера. (Или, по крайней мере, в той мере, в которой существовал интервез, все это находилось в пределах объектов повышенной безопасности Министерства обороны США, поэтому не нужно было много думать о возможности злонамеренных данных.)
После этого для большинства архитектур это было вопросом поддержания совместимости с предыдущими версиями той же архитектуры. Вот почему перевернутые стеки все еще с нами сегодня.
источник
память программы традиционно устанавливается как
куча и стек могут быть обменены
но переполнение буфера все еще может быть использовано, если стек пошел другим путем
взяв классику
strcpy
в качестве примерасо стековой памятью как
это будет означать, что когда копирование завершено, адрес возврата для
strcpy
находится после буфера (вместоfoo
адреса возврата) и может быть перезаписан любым, что находится вin
источник
Некоторое оборудование имеет кучу, начинающуюся с большой памяти, растущую вниз, в то время как стек начинается с маленькой памяти, растущей.
Аппаратура HP PA-RISC, среди прочего, делает это: http://www.embeddedrelated.com/usenet/embedded/show/68749-1.php
Почтенная операционная система Multics работала на оборудовании, на котором (возможно, много) стеки росли: см. Http://www.acsac.org/2002/papers/classic-multics.pdf , конец раздела 2.3.2:
Это довольно интересное утверждение. Не стали ли переполнения буфера такой огромной проблемой только из-за «обычной» схемы процедуры вызова-стека-фрейма? Кроме того, сколько репутации Multics как полностью неуязвимого было просто случайностью аппаратного дизайна?
источник