【问题标题】:Is there a way in std C to tell if I can dereference a pointer safely标准 C 中有没有办法告诉我是否可以安全地取消引用指针
【发布时间】:2012-04-18 22:10:11
【问题描述】:

考虑以下几点:

int * i = malloc(sizeof(int));
free(i);

我现在处于i 指向已释放内存的场景中,但它也非零;这是 C 编程中的一个常见错误,有没有办法在我去做类似的事情之前告诉 i 仍然是一个有效的指针:

*i++; //probable EXC_BAD_ACCESS crash

我知道完全不可能有 100% 可靠(无误报)的方法,除非您从未重用内存;但是大部分时间都有效的东西对于调试来说非常有用。

编辑

我并不是说您不应该将指针设置为 NULL,我只是想知道是否有一种可移植(POSIXish)的方式来戳地址而不会造成灾难性影响,我只是对调试复杂的多线程问题感兴趣不时出现。

【问题讨论】:

  • 始终在free 之后将i 设置为NULL,并在取消引用之前测试它是否为NULL
  • 简单回答:不。复杂的答案:不。
  • @Anthales 只要你只有一个对指针的引用就可以工作,我注意到这是一个编程错误。
  • 这可能是真的,但是如果您有多个指向同一个对象的指针,则无论如何您都需要考虑所有指针。所以在这种情况下,理查兹的评论适用。
  • FWIW,我不同意这种“总是将事物设置为空”的废话。当指针超出范围,或者当它所属的结构被释放时释放指针。然后,是否将其设置为 null 并不重要,因为您已经设计了代码,因此无论如何您都不会再次使用它。比围绕可能为空或不为空的指针更安全,因为它们的用户必须一直检查。例外情况是在执行诸如清除缓存而不销毁缓存之类的操作时——然后您想释放它,并将其设置为 null 以表示不再存在任何内容。

标签: c debugging pointers exception-handling


【解决方案1】:

要获得适用于调试的东西,您需要使用 valgrind 的 memcheck 工具。访问发生时,您会看到无效读取或无效写入错误。

@Anthales 是对的,您需要在释放后立即将指针设置为 NULL。如果您对指针有多个引用,这会变得更加复杂。在不了解您的具体情况的情况下,我无法确切说明如何执行此操作,但可能的解决方案是为不同的结构提供一些东西,允许它们请求对该内存的引用而不是特定的指针。

【讨论】:

  • 将指针设置为 NULL 是一种很好的做法。在许多不同的层面上,出于许多不同的原因。
【解决方案2】:

没有。

静态分析和实时工具(例如 valgrind 和 guard malloc)可以帮助您解决这个问题。改变编写程序的方式也有助于更轻松地了解所有权和生命周期。

如果您真的想要更详细地了解此功能,您可以使用自定义分配器 - 但现有的工具可以提供很大帮助。

【讨论】:

    【解决方案3】:

    没有(可移植的)方法可以从指针值本身知道非 NULL 指针值是否有效。同样,没有(便携式)方法可以知道指针是否指向具有自动、静态或动态范围的对象。如果您非常熟悉您的平台的内存模型,您可能会做出一些有根据的猜测(即,0x00000001 可能不是一个有效的内存位置),但仅此而已。

    您必须独立于指针本身来跟踪所有这些信息,或者在如何使用指针时执行一些纪律。

    【讨论】:

      【解决方案4】:

      您在 C 中真正能做的就是传递足够的信息来了解 i 是否仍然指向某个东西。

      从哲学上讲,如果你不知道*i++; 是否仍然指向可以安全递增的东西,那么即使确实如此,你怎么知道递增它是正确的?

      这与 C 中的数组使用情况类似:您养成了传递数据指针和伴随的大小指示符的习惯。或者你将它们都包装成一个结构。

      如果您可以举一个更大的例子来说明如何使用i,人们可以推荐一种惯用的方式来添加您需要的附加信息。

      【讨论】:

        【解决方案5】:

        有些人喜欢在free 之后将释放的指针设置为NULL

        #define paranoid_free(ptr)    (free(ptr), (ptr) = NULL)
        

        这有利于避免双重释放问题,因为free(NULL) 在 C 中定义(作为无操作)。但它仍然不会阻止您取消引用指针并在程序的其他地方调用未定义的行为。

        【讨论】:

        • 在我拥有的 C89 引用中(我不记得我从哪里得到它),free() 的描述说:“如果 ptr 是空指针,则不会发生任何操作。”跨度>
        • @pmg 感谢纠正我,我以为是这种情况。显然我应该仔细检查一下,因为 C89 中的行为确实是一样的。
        猜你喜欢
        • 1970-01-01
        • 2012-12-14
        • 1970-01-01
        • 2015-05-21
        • 1970-01-01
        • 2017-08-18
        • 2011-02-13
        • 1970-01-01
        相关资源
        最近更新 更多