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

Я спросил Google и провел некоторое исследование по Stackru. Мой вопрос заключается в том, что, когда я вхожу в 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 или что-то подобное, возможно, шансы достаточно близки к Блэкджеку, так что кто-то может быть соблазн играть, чтобы выиграть (так сказать).

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

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

Другие вопросы по тегам