如果指定的指针是"有效的",有没有办法确定(当然是以编程方式)?检查NULL很简单,但像0x00001234这样的东西呢?当试图取消引用这种指针时,会发生异常/崩溃.
首选跨平台方法,但平台特定(适用于Windows和Linux)也可以.
更新澄清: 问题不在于陈旧/释放/未初始化的指针; 相反,我正在实现一个从调用者获取指针的API(比如指向字符串的指针,文件句柄等).调用者可以(有意或无意地)发送无效值作为指针.如何防止崩溃?
更新澄清:问题不在于陈旧,释放或未初始化的指针; 相反,我正在实现一个从调用者获取指针的API(比如指向字符串的指针,文件句柄等).调用者可以(有意或无意地)发送无效值作为指针.如何防止崩溃?
你无法进行检查.你根本无法检查指针是否"有效".你必须相信,当人们使用带指针的函数时,那些人就会知道他们在做什么.如果他们将0x4211作为指针值传递给你,那么你必须相信它指向地址0x4211.如果他们"意外地"击中一个物体,那么即使你会使用一些可怕的操作系统功能(IsValidPtr或其他),你仍然会陷入一个错误并且不会快速失败.
开始使用空指针发信号通知这种事情并告诉你的库的用户,如果他们倾向于意外地传递无效指针,他们不应该使用指针,严重:)
防止调用者发送无效指针导致的崩溃是制作难以找到的静默错误的好方法.
对于使用你的API的程序员来说,通过崩溃而不是隐藏它来获取他的代码是假的明确信息,这不是更好吗?
在Win32/64上有一种方法可以做到这一点.尝试读取指针并捕获将在失败时抛出的结果SEH异常.如果它没有抛出,那么它是一个有效的指针.
但是,这种方法的问题在于它只返回您是否可以从指针读取数据.它不保证类型安全性或任何数量的其他不变量.一般来说,除了说"是的,我可以在现在已经过去的时间内读取内存中的特定位置"之外,这种方法对其他一切都很好.
总之,不要这样做;)
Raymond Chen有一篇关于这个主题的博客文章:http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx
以下是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年内被弃用.
AFAIK没有办法.您应该尝试通过在释放内存后始终将指针设置为NULL来避免这种情况.
看看这个和这个问题.还要看看智能指针.
关于这个帖子中的答案:
用于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进程而不是主进程.
首先,我没有看到任何意图试图保护自己免受故意试图导致崩溃的来电者.他们可以通过尝试通过无效指针本身来轻松完成此操作.还有很多其他方法 - 它们可能只是覆盖你的内存或堆栈.如果您需要防止此类事情,那么您需要使用套接字或其他IPC进行通信,在单独的进程中运行.
我们编写了大量软件,允许合作伙伴/客户/用户扩展功能.不可避免地首先向我们报告任何错误,因此能够轻松地显示问题在插件代码中是有用的.此外,存在安全问题,一些用户比其他用户更受信任.
我们根据性能/吞吐量要求和可信度使用许多不同的方法.从最喜欢的:
使用套接字的单独进程(通常将数据作为文本传递).
使用共享内存的单独进程(如果要传递大量数据).
同一进程通过消息队列分隔线程(如果是频繁的短消息).
相同进程的单独线程都传递了从内存池分配的数据.
通过直接过程调用的相同过程 - 从内存池分配的所有传递数据.
在处理第三方软件时,我们绝不会诉诸于您尝试做的事情 - 特别是当我们将插件/库作为二进制而不是源代码时.
在大多数情况下使用内存池非常容易,并且不需要低效.如果您首先分配数据,那么根据您分配的值检查指针是微不足道的.您还可以存储已分配的长度,并在数据之前和之后添加"magic"值,以检查有效的数据类型和数据溢出.