【问题标题】:Checking if something was malloced检查是否有东西被分配
【发布时间】:2008-11-09 22:48:16
【问题描述】:

给定一个指向某个变量的指针.. 有没有办法检查它是静态分配的还是动态分配的?

【问题讨论】:

  • 出于好奇,是什么激发了这样做的愿望?
  • 我正在制作一个基本上可以摆脱结构的方法。它有一个数据成员,它是指向可能会或可能不会被分配的东西的指针.. 取决于哪个,我想释放它

标签: c malloc


【解决方案1】:

引用您的评论:

我正在制作一个基本上可以摆脱结构的方法。它有一个数据成员,它是指向可能会或可能不会被分配的东西的指针..取决于哪个,我想释放它

正确的方法是在结构中添加另一个成员:一个指向释放函数的指针。

这不仅仅是静态分配与动态分配。有几个可能的分配器,malloc() 只是其中之一。

在类 Unix 系统上,它可能是:

  • 一个静态变量
  • 在堆栈上
  • 在堆栈上但动态分配(即alloca()
  • 在堆上,分配有malloc()
  • 在堆上,分配有new
  • 在堆上,在分配有new[] 的数组中间
  • 在堆上,在分配有malloc() 的结构内
  • 在堆上,在使用new 分配的对象的基类中
  • 分配给mmap
  • 使用自定义分配器分配
  • 更多选项,包括上述几种组合和变体

在 Windows 上,您还拥有多个运行时,LocalAllocGlobalAllocHeapAlloc(您可以轻松创建多个堆)等等。

对于您使用的分配器,您必须始终使用正确的释放函数来释放内存。因此,负责分配内存的程序部分也应该释放内存,或者您必须将正确的释放函数(或围绕它的包装器)传递给将释放内存的代码。

您也可以通过要求始终使用特定分配器分配指针或自己提供分配器(以函数的形式分配内存并可能以函数的形式释放它)来避免整个问题。如果您自己提供分配器,您甚至可以使用技巧(如标记指针)来允许也使用静态分配(但我不会在这里详细介绍这种方法)。

Raymond Chen 有一篇关于它的博文(以 Windows 为中心,但概念在任何地方都相同):Allocating and freeing memory across module boundaries

【讨论】:

    【解决方案2】:

    ACE 库在所有地方都可以做到这一点。您也许可以检查他们是如何做到的。一般来说,您可能一开始就不需要这样做......

    【讨论】:

      【解决方案3】:

      由于堆、栈和静态数据区域通常占用不同范围的内存,因此可以在熟悉进程内存映射的情况下查看地址并确定它位于哪个分配区域。这种技术是特定于体系结构和编译器的,因此它使您的代码移植更加困难。

      【讨论】:

        【解决方案4】:

        大多数 libc malloc 实现通过在每个返回的内存块之前存储一个标头来工作,该标头具有字段(由 free() 调用使用),其中包含有关块大小的信息,以及一个“神奇”值。这个神奇的值是为了防止用户意外删除未分配的指针(或释放被用户覆盖的块)。它是非常特定于系统的,因此您必须查看 libc 库的实现才能确切了解其中的神奇价值。

        一旦你知道了,你将给定的指针移回指向标题,然后检查它的魔法值。

        【讨论】:

        • 这个建议很有趣,但不是解决问题的好方法:malloc() 实现通常只在调试模式下执行此操作,在指针可能具有未定义行为之前访问内存并且魔法值可能存在碰巧。即使在调试模式下使用特定的分配器,您也无法确定指针是否可以安全地传递给free()
        【解决方案5】:

        你能像 malloc 调试器那样,使用 LD_PRELOAD 或其他东西连接到 malloc() 本身吗?如果是这样,您可以保留所有已分配指针的表并使用它。否则,我不确定。有没有办法获取malloc的记账信息?

        【讨论】:

          【解决方案6】:

          不是标准功能。
          malloc 库的调试版本可能具有执行此操作的某些功能。

          【讨论】:

            【解决方案7】:

            您可以将它的地址与您知道的静态地址进行比较,并说它仅在距离很远、知道它应该来自的范围时才被分配,但如果它的范围未知,您就不能真正信任那个。

            【讨论】:

              【解决方案8】:

              1.) 为你拥有的代码获取一个映射文件。

              2.) 底层进程/硬件目标平台应该有一个内存映射文件,该文件通常指示 - 内存的起始地址(堆栈、堆、global0、该块的大小、该内存块的读写属性。

              3.) 从 1.) 中的 mao 文件中获取对象(指针变量)的地址后,尝试查看该地址属于哪个块。你可能会有一些想法。

              =广告

              【讨论】:

                猜你喜欢
                • 2012-06-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-01-09
                • 2012-05-11
                相关资源
                最近更新 更多