当前位置:  开发笔记 > 编程语言 > 正文

测试有效性指针(C/C++)

如何解决《测试有效性指针(C/C++)》经验,为你挑选了8个好方法。

如果指定的指针是"有效的",有没有办法确定(当然是以编程方式)?检查NULL很简单,但像0x00001234这样的东西呢?当试图取消引用这种指针时,会发生异常/崩溃.

首选跨平台方法,但平台特定(适用于Windows和Linux)也可以.

更新澄清: 问题不在于陈旧/释放/未初始化的指针; 相反,我正在实现一个从调用者获取指针的API(比如指向字符串的指针,文件句柄等).调用者可以(有意或无意地)发送无效值作为指针.如何防止崩溃?



1> Johannes Sch..:

更新澄清:问题不在于陈旧,释放或未初始化的指针; 相反,我正在实现一个从调用者获取指针的API(比如指向字符串的指针,文件句柄等).调用者可以(有意或无意地)发送无效值作为指针.如何防止崩溃?

你无法进​​行检查.你根本无法检查指针是否"有效".你必须相信,当人们使用带指针的函数时,那些人就会知道他们在做什么.如果他们将0x4211作为指针值传递给你,那么你必须相信它指向地址0x4211.如果他们"意外地"击中一个物体,那么即使你会使用一些可怕的操作系统功能(IsValidPtr或其他),你仍然会陷入一个错误并且不会快速失败.

开始使用空指针发信号通知这种事情并告诉你的库的用户,如果他们倾向于意外地传递无效指针,他们不应该使用指针,严重:)



2> Nailer..:

防止调用者发送无效指针导致的崩溃是制作难以找到的静默错误的好方法.

对于使用你的API的程序员来说,通过崩溃而不是隐藏它来获取他的代码是假的明确信息,这不是更好吗?


但在某些情况下,在调用API时会立即检查错误指针_is_如何提前失败.例如,如果API将指针存储在数据结构中,以后它只会被引用,该怎么办?然后传递API一个坏指针将导致稍后随机点崩溃.在这种情况下,最好在最初引入错误值的API调用中更快失败.
+1提前失败并且加载始终是最佳选择!

3> JaredPar..:

在Win32/64上有一种方法可以做到这一点.尝试读取指针并捕获将在失败时抛出的结果SEH异常.如果它没有抛出,那么它是一个有效的指针.

但是,这种方法的问题在于它只返回您是否可以从指针读取数据.它不保证类型安全性或任何数量的其他不变量.一般来说,除了说"是的,我可以在现在已经过去的时间内读取内存中的特定位置"之外,这种方法对其他一切都很好.

总之,不要这样做;)

Raymond Chen有一篇关于这个主题的博客文章:http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx


如果将"有效指针"定义为"不会导致访问冲突/段错误",那么这只是"正确答案".我更愿意将其定义为"指向分配用于您将要使用它的目的的有意义数据".我认为这是指针有效性的更好定义......;)
@Tim,在C++中无法做到这一点.
@Christopher,非常真实.我应该说"我可以在现在已经过去的时候读到记忆中那个特定的地方"

4> George Carre..:

以下是Linux下C程序的三种简单方法,可以对其运行的内存状态进行内省,以及为什么在某些情况下问题具有适当的复杂答案.

    在调用getpagesize()并将指针四舍五入到页边界之后,可以调用mincore()来查明页面是否有效以及它是否恰好是进程工作集的一部分.请注意,这需要一些内核资源,因此您应该对其进行基准测试,并确定在您的api中调用此函数是否真的合适.如果你的api将处理中断,或者从串口读入内存,那么调用它来避免不可预测的行为是合适的.

    在调用stat()以确定是否有/ proc/self目录可用之后,您可以fopen并通过/ proc/self/maps读取以查找有关指针所在区域的信息.研究proc的手册页,进程信息伪文件系统.显然这是相对昂贵的,但您可以通过将解析结果缓存到一个数组中,您可以使用二进制搜索有效地查找.还要考虑/ proc/self/smaps.如果您的api用于高性能计算,那么程序将需要了解/ proc/self/numa,这是在numa的手册页(非统一内存架构)下记录的.

    get_mempolicy(MPOL_F_ADDR)调用适用于高性能计算api工作,其中有多个执行线程,并且您正在管理您的工作以与非统一内存关联,因为它与cpu核心和套接字资源相关.这样的api当然也会告诉你指针是否有效.

在Microsoft Windows下,有一个功能QueryWorkingSetEx,它记录在Process Status API下(也在NUMA API中).作为复杂的NUMA API编程的必然结果,这个函数也可以让你做一个简单的"测试有效性指针(C/C++)"工作,因此它不可能在至少15年内被弃用.


第一个答案不是试图对问题本身进行讨论,而是实际上完美地回答了问题.人们有时候并没有意识到人们真的需要这种调试方法来查找例如第三方库或遗留代码中的错误,因为即使valgrind在实际访问它们时也只能找到指针,例如,如果你想定期检查指针的有效性在缓存表中,已从代码中的其他位置覆盖...

5> Ferdinand Be..:

AFAIK没有办法.您应该尝试通过在释放内存后始终将指针设置为NULL来避免这种情况.


将指针设置为null不会给你任何东西,除了可能是错误的安全感.
int*p = new int(0); int*p2 = p; 删除p; p = NULL; 删除p2; //崩溃
如果您对指向的内存有别名,则只有其中一个设置为NULL,其他别名悬空.

6> tunnuz..:

看看这个和这个问题.还要看看智能指针.



7> Fredrik..:

关于这个帖子中的答案:

用于Windows的IsBadReadPtr(),IsBadWritePtr(),IsBadCodePtr(),IsBadStringPtr().

我的建议是远离他们,有人已经发布了这个:http: //blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

关于同一主题和同一作者(我认为)的另一篇文章是这一篇:http: //blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx("IsBadXxxPtr应该被称为CrashProgramRandomly ").

如果您的API用户发送错误数据,请让它崩溃.如果问题是直到稍后才使用传递的数据(并且这使得查找原因更加困难),请添加调试模式,其中在条目处记录字符串等.如果它们很糟糕,那将是显而易见的(并且可能会崩溃).如果它经常发生,可能值得将API移出进程并让它们崩溃API进程而不是主进程.



8> Dipstick..:

首先,我没有看到任何意图试图保护自己免受故意试图导致崩溃的来电者.他们可以通过尝试通过无效指针本身来轻松完成此操作.还有很多其他方法 - 它们可能只是覆盖你的内存或堆栈.如果您需要防止此类事情,那么您需要使用套接字或其他IPC进行通信,在单独的进程中运行.

我们编写了大量软件,允许合作伙伴/客户/用户扩展功能.不可避免地首先向我们报告任何错误,因此能够轻松地显示问题在插件代码中是有用的.此外,存在安全问题,一些用户比其他用户更受信任.

我们根据性能/吞吐量要求和可信度使用许多不同的方法.从最喜欢的:

使用套接字的单独进程(通常将数据作为文本传递).

使用共享内存的单独进程(如果要传递大量数据).

同一进程通过消息队列分隔线程(如果是频繁的短消息).

相同进程的单独线程都传递了从内存池分配的数据.

通过直接过程调用的相同过程 - 从内存池分配的所有传递数据.

在处理第三方软件时,我们绝不会诉诸于您尝试做的事情 - 特别是当我们将插件/库作为二进制而不是源代码时.

在大多数情况下使用内存池非常容易,并且不需要低效.如果您首先分配数据,那么根据您分配的值检查指针是微不足道的.您还可以存储已分配的长度,并在数据之前和之后添加"magic"值,以检查有效的数据类型和数据溢出.

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有