Почему адреса локальных переменных могут быть разными каждый раз?

Я спросил Google и сделал некоторые исследования по StackOverflow. Мой вопрос в том, что когда я вхожу в main() функция в программе на C++ и объявляет самую первую переменную, почему адрес этой переменной может меняться при разных исполнениях? См. мой пример программы ниже:

#include <iostream>

int main() {
    int *a = new int;
    int *b = new int;

    std::cout << "address: " << a << " " << b << std::endl;
    std::cout << "address of locals: " << &a << " " << &b << std::endl;
    return 0;
}

результат на исполнение 1:

address: 0xa32010 0xa32030
address of locals: 0x7fff10de2cf0 0x7fff10de2cf8

результат на исполнение 2:

address: 0x1668010 0x1668030
address of locals: 0x7ffc252ccd90 0x7ffc252ccd98

результат выполнения 3:

address: 0x10e0010 0x10e0030
address of locals: 0x7ffd3d2cf7f0 0x7ffd3d2cf7f8

как вы можете видеть, я получаю разные результаты при разных казней. Первая строка вывода, соответствующая адресу выделенной памяти, которая должна происходить в куче – если им назначаются разные адреса каждый раз, это имеет для меня смысл. Однако даже когда я печатаю адреса локальных переменных, соответствующие второй строке, результаты все еще различаются.

на первый взгляд, я думал, что это потому, что программа печатает адрес физической памяти, но этот пост,Виртуальная память или физическая память, опровергает мою первоначальную мысль. Есть ли причина, по которой, учитывая, что выполнение программ" то же самое", без потоков, без пользовательских входов и т. д., что все еще есть выделения памяти с разными адресами?

окружающая среда испытания:

  • Linux 14.04
  • Mac OS X 10.10

1 ответов


при выделении в куче (с помощью new оператора или malloc() и друзья), ваша программа должна попросить ОС выделить вашу память кучи. Много закулисных вещей происходит в диспетчере памяти ОС (детали реализации которых в основном выше моего уровня оплаты: сбор мусора, консолидация исправленной памяти и т. д.), И это хорошо не думать об этом.

локальные переменные размещаются в стеке. Традиционно, распределение стека будет повторяемым, но в последние годы это изменилось. рандомизация адресного пространства (ASR) является относительно недавним нововведением в управлении памятью ОС, которое намеренно делает адреса памяти в распределениях стека (например, те, которые вы наблюдали) как недетерминированные, насколько это возможно во время выполнения. Это функция безопасности: это удерживает плохих актеров от использования переполнения буфера кучи, потому что если реализация ASLR достаточно энтропийна, кто знает, что происходит быть там, в конце переполненного буфера?

цена, которую вы платите за эту и другие функции управления памятью,-это контроль. Ставки на адреса распределений на современной (не встроенной) платформе похожи на игру в Powerball: возможно, забавное отвлечение, но не работоспособный план на будущее. Если ваш код работает на платформе AVR-ISA или что-то в этом роде, возможно, шансы достаточно близки к блэкджеку, чтобы кто-то мог соблазниться играть, чтобы выиграть (так что говорить.)

спасибо @T. C. за ссылку и @SergeyA за предложение.