如何使用内置函数而不是 NULL 检查来验证指针?
Posted
技术标签:
【中文标题】如何使用内置函数而不是 NULL 检查来验证指针?【英文标题】:how to validate a pointer using built in functions other than a NULL check? 【发布时间】:2017-08-23 13:04:40 【问题描述】:在今天的讨论中,我发现 VxWorks 和 LynxOS 中有检查,告诉您为指针分配的地址来自有效范围.这是我第一次听说这个代码,就像我分配 int *i=&variable;
一样。
我应该得到一个警告或错误,指出在我的应用程序中我无法将地址值分配给整数。
就像我在进行 NULL 检查时一样,我只检查地址 0x00000000
。但有时地址可能是0x00000001
。如果它是一个未映射的区域并且可能无法访问,这也是一个无效的情况。有没有人知道 Linux 有类似的事情,或者可以指导它在 VxWorks 或 LynxOS 中是如何完成的。
有什么想法吗??
【问题讨论】:
我猜你可以试试mlock
,如果不是映射内存会返回错误...
@Antti Haapala int *i=&variable
将永远是
【参考方案1】:
您在 VxWorks 中寻找的函数称为 vxMemProbe。
基本上,vxMemProbe 库会插入特殊的异常处理代码来捕获页面错误或总线错误。 vxMemProbe 函数用于检查地址是否对读或写有效。它还允许您测试特定地址是否可通过给定的数据宽度(8、16、32、64 位)和对齐方式访问。
vxMemProbe 的底层机制与特定架构的异常处理机制相关联。 vxMemProbe 库将代码插入到异常处理程序中。当您探测触发异常的地址时,处理程序会检查 vxMemProbe 是否触发了异常。如果是这样,则处理程序在异常之前恢复状态处理器并将执行返回到调用 vxMemProbe 的位置,同时还通过给定调用约定的体系结构返回值。
【讨论】:
为什么这被接受为答案?问题是关于在 Linux 上做类似的事情! @BasileStarynkevitch 除了,如果你读了这个问题,最后是...... 或者可以指导它如何在 VxWorks 或 LynxOS 上完成【参考方案2】:如Felix Palmen's answer 中所述,通常你不能做你想做的事。
我应该得到一个警告或错误,指出在我的应用程序中我无法将地址值分配给整数。
静态且可靠地检测所有指针故障是不可能的(因为可以证明它等同于解决halting problem)。顺便说一句,您可能会考虑使用static program analysis 工具,例如Frama-C。
在 Linux 上,原则上,您可以在运行时测试给定地址在您的 virtual address space 中是否有效,例如使用/proc/
,例如通过解析/proc/self/maps
伪文本文件(理解我的意思,在终端中尝试cat /proc/$$/maps
,然后cat /proc/self/maps
)。见proc(5)。在实践中我不建议经常这样做(它可能会太慢),当然它不是编译器的builtin 函数(你应该自己编码)。顺便说一句,请注意ASLR。
但是,有一些工具可以帮助检测(某些)错误地址使用,特别是 valgrind 和 address sanitizer 工具,阅读 GCC 的 instrumentation options 并尝试使用 -fsanitize=address
进行编译...
不要忘记编译带有所有警告和调试信息的代码,所以使用gcc -Wall -Wextra -g
编译它。
顺便说一句,如果您将某个局部变量的地址存储在某个全局指针中,并在该局部变量在范围内之后取消引用该指针,您仍然有一些 undefined behavior(即使您的代码没有崩溃,因为您通常在你的call stack 上取消引用一些随机地址,你应该非常scared。应始终避免使用 UB。
【讨论】:
【参考方案3】:这里有几个误解:
从C语言的角度来看,只有一个指针值保证无效,这就是NULL
。对于其他值,这取决于上下文。当指针指向当前活动的对象时,它是有效的。 (请注意,这在您的 int *i = &variable
示例中是微不足道的,因为只有当 可以从当前范围访问 variable
时,这才是有效的语法)
NULL
不一定表示所有位为零的值。这是最常见的情况,但有些平台可能对NULL
指针使用不同的位模式。 C 标准甚至允许不同类型的指针对NULL
有不同的表示。尽管如此,将0
转换为指针类型保证会产生此类型的NULL
指针。
我不知道您在 VxWorks 中究竟指的是什么,但 Linux 当然会检查内存访问。如果进程试图访问未映射到虚拟地址空间的地址,则会向该进程发送SIGSEGV
信号,这会导致程序立即异常终止(分段错误)。
【讨论】:
@PeterJ_01 又错了。NULL
指针在布尔上下文中的计算结果为 false,无论其表示形式是什么。
@PeterJ_01:编译器不能针对这种情况发出特殊测试。
@Felix Palmen An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66)
@Felix Palmen 快速浏览了一下。标准中的哪里描述了这种行为? wrong again. the NULL pointer evaluates to false in a boolean context, no matter what its representation is
@PeterJ_01 正是您引用的部分。 cast 是一种显式转换,对于这个null 指针 的表示,没有任何说明。 表达式与表示完全不同。以上是关于如何使用内置函数而不是 NULL 检查来验证指针?的主要内容,如果未能解决你的问题,请参考以下文章