Почему стек растет вниз?

31

Я предполагаю, что есть история, но почему стек растет вниз?

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

Mehrdad
источник
3
stackoverflow.com/questions/1677415/… отмечает, что стек может расти в любом случае до некоторой степени.
JB Кинг
6
Есть такой же вопрос: stackoverflow.com/questions/2035568/… . На самом деле, есть гораздо лучший вопрос и ответ на этот вопрос здесь: stackoverflow.com/questions/664744/…
Карлсон
Связанный вопрос не совсем охватывает проблему переполнения буфера.
Deadalnix
1
потому что куча растет вверх.
Tylerl
2
Расположение памяти 0 вверху или внизу?

Ответы:

21

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

Если вам нужно немного больше кучи, вы можете быть осторожны с использованием стека; если вам нужно больше стека, вы можете попытаться освободить кучу памяти. Результатом, конечно, были, в основном, впечатляющие сбои, поскольку стек иногда перезаписывал кучу, и наоборот.

В те времена не было никакого интервала, поэтому не было проблемы использования переполнения буфера. (Или, по крайней мере, в той мере, в которой существовал интервез, все это находилось в пределах объектов повышенной безопасности Министерства обороны США, поэтому не нужно было много думать о возможности злонамеренных данных.)

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

Майк Накис
источник
8
Вернемся дальше в истории, и не было кучи, даже сегодня многие 8- и 16-битные микроконтроллеры не имеют кучи. Стек вырос, так что программа могла быть установлена ​​по низкому адресу памяти, а стек был оставшейся памятью. Инициализация стека может быть выполнена перед загрузкой программы, упрощая программы.
Mattnz
1
У большинства маленьких микроконтроллеров есть куча, но не куча, которая растет. Трудно оправдать использование динамического выделения памяти в куче, когда у вас есть небольшой объем ОЗУ (<1 КБ) для работы. Обычно единственным изменяющимся размером раздела памяти является стек.
Технит
7

память программы традиционно устанавливается как

code
constants
heap (growing up)
...
stack (growing down)

куча и стек могут быть обменены

но переполнение буфера все еще может быть использовано, если стек пошел другим путем

взяв классику strcpyв качестве примера

foo(char* in){
char[100] buff;
strcpy(buff,in);
}

со стековой памятью как

ret foo
arg in
buff array
ret strcpy
buf pointer
in

это будет означать, что когда копирование завершено, адрес возврата для strcpyнаходится после буфера (вместо fooадреса возврата) и может быть перезаписан любым, что находится вin

чокнутый урод
источник
4

Некоторое оборудование имеет кучу, начинающуюся с большой памяти, растущую вниз, в то время как стек начинается с маленькой памяти, растущей.

Аппаратура 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 росли в положительном направлении, а не в отрицательном направлении. Это означало, что если бы вы на самом деле достигли переполнения буфера, вы бы перезаписывали неиспользуемые стековые фреймы, а не собственный указатель возврата, что значительно усложняло бы использование.

Это довольно интересное утверждение. Не стали ли переполнения буфера такой огромной проблемой только из-за «обычной» схемы процедуры вызова-стека-фрейма? Кроме того, сколько репутации Multics как полностью неуязвимого было просто случайностью аппаратного дизайна?

Брюс Эдигер
источник
Что ж, отсутствие исполняемого стека (ов), вероятно, помогло Multics так же, как интеллектуальное направление стека, и, конечно же, во многих программах, написанных на PL / 1, переполнение строк также не было проблемой.
Грег А. Вудс