如何避免访问已释放的地址?

时间:2012-12-29 05:37:56

标签: c linux memory

当我尝试访问已经释放的地址时,程序将正常运行。有些货物要避免吗?比如名为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。

4 个答案:

答案 0 :(得分:11)

不,你必须自己照顾好这个 从技术上讲,从语言标准的角度来看,写入不属于您的内存位置是未定义行为

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

理由是:

“更大的力量带来了更大的责任”

所以你的责任就在于你。

答案 1 :(得分:8)

p就像一个普通变量

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

  

p = NULL;

所以请记住以下提示:

  1. 每次使用指针之前,请检查它是否为NULL指针。
  2. 每次释放记忆后,将指针设为NULL。

答案 2 :(得分:2)

  • 释放后将NULL指定给指针。
  • 访问前请检查NULL

答案 3 :(得分:1)

除了其他回复之外,您可以考虑使用Boehm's conservative garbage collector,然后使用GC_malloc代替malloc,您将不会执行任何free(甚至如果,当绝对确定内存区域变得无用且无法访问时,您可以明确地GC_free它。

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

关于“为什么有时你仍然会访问一个无效的地址”(在free - d区域内)的问题,答案是特定于实现的。实际上,在Linux上,从内核获取内存是通过mmap(2)(或有时是sbrk(2))完成的,然后通过munmap(2)系统调用来完成释放,这是一些昂贵的操作和处理多个页面长度(通常为4Kbytes)。因此malloc实现会尝试避免执行大量mmapmunmap系统调用,因此通常会以不同方式管理free - d内存区域,方法是将它们组织起来以便它们可以在没有进行任何malloc系统调用的情况下由另一个mmap重用。这解释了内存区域仍然存在(即使它在malloc内部簿记内),您可以访问它。但这样做会破坏malloc的内部不变量,并且会在以后发生破坏。

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

尝试strace您的简单程序,以了解它正在做什么系统调用。