c++ - 为什么每次局部变量的地址都不一样?

标签 c++ c memory virtual-memory aslr

我已经询问了 Google,并对 StackOverflow 进行了一些研究。我的问题是,当我在 C++ 程序中输入 main() 函数并声明第一个变量时,为什么这个变量的地址会因不同的执行而不同?请参阅下面的示例程序:

#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

如您所见,我在不同的执行过程中得到不同的结果。输出的第一行对应于分配内存的地址,这应该发生在堆中——如果它们每次都分配不同的地址,这对我来说有点道理。然而,即使我打印了局部变量的地址——对应于第二行——结果仍然不同。

乍一看,我以为是因为程序正在打印物理内存地址,但这篇文章,Virtual Memory or Physical Memory ,反驳了我最初的想法。鉴于程序的执行是“相同的”,没有线程、没有用户输入等,是否有任何理由仍然存在具有不同地址的内存分配?

测试环境:

  • Linux 14.04
  • Mac OS X 10.10

最佳答案

在堆上分配时(使用 new 运算符或 malloc() 和 friend ),您的程序必须要求操作系统分配您的堆内存。操作系统内存管理器中发生了很多幕后的事情(其实现细节大多超出我的工资等级:垃圾收集、回收内存的整合等),这是一件好事 不必考虑。

局部变量在栈上分配。传统上,堆栈分配是可重复的,但近年来这种情况发生了变化。 Address space layout randomization (ASR) 是 OS 内存管理中相对较新的创新,它故意使堆栈分配中的内存地址(例如您观察到的那些)在运行时尽可能地不确定。这是一个安全特性:这可以防止不良行为者利用堆缓冲区溢出,因为如果 ASLR 实现足够熵,谁知道溢出缓冲区的末尾会发生什么?

您为此和其他内存管理功能付出的代价是控制权。在现代(非嵌入式)平台上投注分配地址就像玩强力球:可能是一种有趣的分心,但不是 future 可行的计划。如果您的代码在 AVR-ISA 平台或类似平台上运行,则可能与 Blackjack 的赔率更接近,以至于有人可能会被诱骗获胜(可以这么说)。

无论如何,就我个人而言,我不是赌徒——正如我常说的,绅士们更喜欢堆栈分配。但这基本上就是您获得这些结果的原因。

感谢@T.C.链接和@SergeyA 的建议。

关于c++ - 为什么每次局部变量的地址都不一样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34908728/

相关文章:

java - jmap直方图中的这些对象是什么?

memory - 由于自定义启动器,设置 Java 应用程序的虚拟机最大内存而无需访问 VM 参数?

C++获取单链表中匹配节点的前一个节点

c++ - 猜猜输出。 (字符数组的声明/初始化)

Windows 上的 Python C 扩展。错误 : not found vcvarsall. bat

使用 execvp 进行 c 编程

c++ - 编程语言函数在内存中位于哪里?

c++ - 使用 C++ 绑定(bind)编译 OpenCL

c# - 如何从托管代码项目中调试 native 代码项目? C++/C#

c - C中最后一个fread()中的信息大小