如何使用内置函数而不是 NULL 检查来验证指针?

Posted

技术标签:

【中文标题】如何使用内置函数而不是 NULL 检查来验证指针?【英文标题】:how to validate a pointer using built in functions other than a NULL check? 【发布时间】:2017-08-23 13:04:40 【问题描述】:

在今天的讨论中,我发现 VxWorksLynxOS 中有检查,告诉您为指针分配的地址来自有效范围.这是我第一次听说这个代码,就像我分配 int *i=&variable; 一样。

我应该得到一个警告或错误,指出在我的应用程序中我无法将地址值分配给整数。

就像我在进行 NULL 检查时一样,我只检查地址 0x00000000。但有时地址可能是0x00000001。如果它是一个未映射的区域并且可能无法访问,这也是一个无效的情况。有没有人知道 Linux 有类似的事情,或者可以指导它在 VxWorksLynxOS 中是如何完成的。

有什么想法吗??

【问题讨论】:

我猜你可以试试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 检查来验证指针?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何检查指针是不是为 NULL 指针?

我可以使用 if (pointer) 而不是 if (pointer != NULL) 吗?

C语言中free掉一段空间后为啥还要使用NULL

golang 内置函数new()

使用功能指针的STL映射

如何检查双指针中的空白空间(NULL)