【问题标题】:how to avoid visiting a freed address?如何避免访问已释放的地址?
【发布时间】:2012-12-29 05:37:55
【问题描述】:

当我尝试访问一个已经被释放的地址时,程序会正常运行。有什么需要避免的商品吗?像一些名为 have_alloca(void *p) 的函数可以返回 p 是否是有效地址。
我知道valgrindtool=memcheck 可以做到这一点。但我想知道我是否可以从代码中避免它。
这是一个简单的例子:

#include <stdlib.h>

int main(int argc, char *argv[])
{
    int *p = malloc(sizeof(int) * 10);
    free(p);
    *(p + 1) = 100;

    return 0;
}

为什么我可以访问无效地址?并且程序可以在没有任何警告的情况下编译和运行。 顺便说一句:Linux。

【问题讨论】:

  • 这和linux有什么关系?
  • @ValekHalfHeart:不是很多,但如果有一个解决方案只适用于 Windows(或 Solaris,或 Mac OS X,或 FreeBSD,或......),它不会有帮助madper,如果有一个仅适用于 Linux 的解决方案,那将会很有帮助。事实上,在任何平台上都没有通用解决方案。
  • 这里是对why the access might work (sometimes)的一些解释

标签: c linux memory


【解决方案1】:

不,您必须自己处理。
从技术上讲,从语言标准的角度来看,写入不属于您的内存位置是未定义行为

C 和 C++ 语言为您提供了访问变量地址并使用它们的灵活性,但您有责任让这些地址包含您的变量/对象拥有的有效值。

理由是:

“权力越大,责任越大”

所以责任是你自己来承担的。

【讨论】:

    【解决方案2】:

    p 就像一个普通的变量

    函数free(p)的调用只是释放了我们分配的内存,但是p仍然持有地址值。除非你自己重置:

    p = NULL;

    所以请记住以下提示:

    1. 每次使用指针前,检查它是否为空指针。
    2. 每次释放内存后,将指针设为NULL。

    【讨论】:

    • 真是个好办法。但是,如果我有两个或多个指针指向同一个区域。然后,我释放它并设置一个指向NULL 的指针。它仍然无法避免我通过其他指针访问它。记住该区域的所有点都非常困难。
    • 维护指针是你的责任。所以,尽量使用干净简单的方式来编写你的代码。
    • @madper 现在您了解了垃圾收集器的好处,它可以减轻您的责任。不幸的是,C 没有提供这样的东西。我还鼓励您接受这个答案,而不是文森特在此处描述的良好做法目前接受的答案。另一个答案没有。
    【解决方案3】:
    • 释放后将NULL分配给指针。
    • 在访问之前检查不是NULL

    【讨论】:

      【解决方案4】:

      除了其他回复,你可以考虑使用Boehm's conservative garbage collector,然后你会使用GC_malloc而不是malloc,并且你不会做任何free(即使,当绝对确定记忆zone 变得无用且无法访问,您可以明确地GC_free 它)。

      但是C的重点是你不能使用free-d 数据区。这样做是未定义的行为,任何事情都可能发生。

      关于“为什么有时您仍然可以访问无效地址”的问题(在free-d 区域内),答案是特定于实现的。实际上,在 Linux 上,从内核获取内存是通过 mmap(2)(或有时是 sbrk(2))完成的,并通过 munmap(2) 系统调用完成释放它,这些操作在某种程度上是昂贵的操作并且处理多个页面长度(通常为 4 KB)。所以malloc 实现试图避免做很多mmapmunmap 系统调用,所以通常以不同的方式管理free-d 内存区域,通过组织它们以便它们可以被进一步的malloc 重用而不做任何mmap 系统调用。这说明内存区域仍然存在(即使它在malloc 内部簿记内)并且您可以访问它。但这样做会破坏malloc 的内部不变量,之后会发生严重破坏。

      顺便说一句,地址在地址空间内是有效的,您可以通过(顺序)读取/proc/1234/maps文件(Linux上具有某些指定文本内容的伪文件)来查询进程1234的地址空间。从进程内部读取/proc/self/maps。尝试命令cat /proc/self/maps,它显示了运行cat 命令的进程的地址空间以了解更多信息。请参阅 proc(5) 手册页。

      尝试strace您的简单程序以了解它正在执行的系统调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-03
        • 1970-01-01
        • 2023-03-27
        • 2013-07-22
        • 2011-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多