【问题标题】:How to find whether a given address is in heap or in stack如何查找给定地址是在堆中还是在堆栈中
【发布时间】:2016-02-21 06:15:09
【问题描述】:

我需要查找给定地址是在堆中还是在堆栈中。在 Linux 中是否有可靠的方法来做到这一点?

我考虑过以下方法,假设堆栈将向下增长并且堆将向堆栈增长。这个解决方案的可靠性如何?我们不使用gcc split-stack

is_stack (void *addr) {
   int a;
   if( &a < addr) return stack;
   else return heap
}

[编辑 - 我看到了一个类似的问题,但这更像是一个理论上的问题]

【问题讨论】:

  • 你到底为什么要问?
  • ASLR 将堆栈放置在虚拟内存空间中的某个随机位置,并将堆放置在其他随机位置。所以你不能假设堆栈地址和堆地址之间有任何关系。
  • 不,堆栈增长的方向主要取决于处理堆栈的处理器指令,特别是调用/返回和推送/弹出指令。在大多数处理器上,堆栈会不断增长,但您不能依赖它(如果您想要可移植的面向未来的代码)。
  • 我不禁觉得您要解决的实际问题需要不同的方法。你的problem X是什么?

标签: c linux unix gcc


【解决方案1】:

首先,您的process 中可能有多个堆栈,特别是如果它是多线程的(并且某些库可以在您不要求的情况下启动线程)。而且您的进程'virtual address space 可能有更多的段,而不仅仅是 heapstack

您可能会解析 /proc/self/maps 伪文件。见proc(5)。请注意,由于它是由内核生成的伪文件,因此不涉及物理 IO,并且读取和解析 /proc/self/maps 文件应该非常快。

你的进程的地址映射可以通过调用mmap(2)munmapexecvemprotect和其他一些系统调用来改变(见syscalls(2) 获取它们的列表);使用strace(1) 了解哪些系统调用已完成。对malloc(由许多函数在内部调用,包括fopen...)或free(以及dlopen 等...)的任何调用可以(但赢了'不总是)使用它们,因此缓存解析 /proc/self/maps 的结果不是一个可靠的选择。

首先在终端中尝试cat /proc/$$/maps 命令(向您显示您的shell 的虚拟地址空间的描述)。

正如许多评论的那样,因为ASLR,即使只有一个堆栈,您也不知道堆栈和堆的相对位置。一个可能的技巧可能是在你的main 开始时将一些局部变量的地址(甚至mainargc 第一个参数,或argv[0])放在一些全局void*stackbottom; 中,然后稍后像您一样比较地址,即测试if( &amp;a &lt; addr &amp;&amp; &amp;a &gt; stackbottom)。请注意,Boehm's garbage collector 正在做类似的事情。

但最可靠的方法是读取和解析/proc/self/maps,这应该相当快,而且肯定是一种编程解决方案(内核是动态提供有关其状态和进程状态的信息。 /proc/ 并且没有物理 IO 参与读取它)。

而且,在堆栈或堆中是指针的定义不明确的属性(换句话说,stackheap 是一个比你想象的)。您需要更准确地了解您真正想做的事情。

或者,重新定义您自己的mallocfree 等并让您的malloc 管理一些内存映射。

【讨论】:

  • 感谢您的回答!假设这是一个受控的单线程环境。不,proc 不是解决方案。我想以编程方式进行。想评论我发布的解决方案吗?
  • 相反,阅读/proc/self/maps是最可靠的程序化方案。
  • 感谢您的技巧。这个逻辑将成为性能非常关键的部分。基于此,我需要释放某些内存。每次都解析 proc/map 看起来不像是一个解决方案。解析一次 proc/maps 并保留数据似乎很好。
  • 但是地图正在改变,并且可能在任何mallocfreedlopenmmap发生变化
  • @joe:您是否考虑过简单地使用 Boehm 的 GC:将所有对 malloc 的调用替换为 GC_malloc 并删除对 free 的所有调用。
【解决方案2】:

C 标准没有 heapstack 的概念,因此语言本身无法告诉您。

但是您确实提到了 Linux,所以一切都不会丢失 - 您可以通过大量工作来实现这一点。

如果您将定义为malloc分配的内存,您可以考虑构建自己的内存分配系统。许多 C 编译器允许您在链接时为链接到您的程序的 all 库注入不同的malloc,因此这种方法非常可行。 (见 LD_PRELOAD)。当然,替换 malloc 的主要内容将简单地调用标准函数。但另一部分将维护一个已分配内存的表。您可以在需要编写的测试函数中使用该信息。

您需要对callocfree 等执行相同操作。

【讨论】:

  • 感谢您的建议。我正在寻找与我发布的解决方案一样简单的东西。你能告诉我为什么这行不通吗?
  • 为什么呢?它基于您的假设,您无法在标准的上下文中证明这一点。我也不喜欢&amp;a &lt; addr:如果addr 没有作为指向int 的指针开始生活,那就是UB(我认为)。
  • 哦,不。首先,将其视为伪代码。我们正在尝试比较这里的地址。让我们不要担心类型。关键是逻辑是否有效。
  • 我看不到它工作。假设是不正确的。顺便说一句,你的问题没有错。
  • @joe “新平台”到底是什么意思?堆栈和堆的位置看起来倒置可能有各种原因。如果您使用不同的处理器架构、不同的操作系统甚至不同的编译器,ASLR 并不是唯一可能的原因。事实仍然是,这个问题与特定的实现密切相关。正如这个答案中所指出的,“堆栈”和“堆”并没有真正在 C 中定义,这意味着您不能编写一个保证适用于所有实现的函数版本。
猜你喜欢
  • 2012-11-23
  • 1970-01-01
  • 2010-11-06
  • 2014-12-21
  • 2010-11-15
  • 2016-02-04
  • 2021-05-25
  • 2013-03-04
  • 2011-04-08
相关资源
最近更新 更多