【问题标题】:Why the addresses of local variables can be different every time?为什么每次局部变量的地址都不一样?
【发布时间】:2016-01-20 19:24:15
【问题描述】:

我已经询问了 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

【问题讨论】:

  • 一方面,ASLR 可能有所贡献——它是否在您的测试系统的内核中启用?
  • 是的,这几乎可以肯定是ASLR 在工作。
  • @fish2000,您当然应该将此作为答案添加一些解释。
  • 非确定性编译器优化在这里也可能会搞砸。
  • @Sergey 完成了,谢谢!

标签: c++ c memory virtual-memory aslr


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 顺便说一句,ASLR 也适用于堆栈位置,这就是为什么局部变量在每次执行时也有不同的地址。这正是问题所在。
  • @JordanMelo 好点——我确实假设对诸如此类的术语有一个随意的理解。答案中的“堆栈”和“堆”——但是是的,程序的堆栈本身确实是由内存管理器使用 ASLR 初始化的,我完全是想说这个事实,谢谢
  • 当您谈到 ASLR 作为一项安全功能时,您的意思是说它可以防止基于堆栈的缓冲区溢出(而不是堆)吗?我想这是它解决的主要漏洞。
  • @Banex:它可以防止两者。本地地址和堆地址都会有所不同。
猜你喜欢
  • 1970-01-01
  • 2021-09-04
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多