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

时间:2022-06-18 04:09:14

During a discussion today I came across that there are checks in the VxWorks and in LynxOS which tells you that the address you assign for a pointer is from a valid range. This the first time I am hearing about this code like I assign int *i=&variable;.

在今天的一次讨论中,我无意中发现在VxWorks和LynxOS中存在检查,这些检查告诉您为指针分配的地址来自一个有效范围。这是我第一次听到像分配int * I =&variable这样的代码。

I should get a warning or error which says that In my application I cannot assign the address value to the integer.

我应该得到一个警告或错误,说明在我的应用程序中,我不能将地址值赋给这个整数。

Like while I do a NULL check I am only checking the address 0x00000000. But there can be the case the address might be 0x00000001. Which is also an invalid case if its an unmapped area and might not be accessible. Is any one aware of some thing similar for Linux or can guide how its done in VxWorks or LynxOS.

就像我做空检查时,我只检查地址0x00000000。但也可能是地址可能是0x00000001。如果它是一个未映射的区域,并且可能无法访问,那么它也是无效的。有没有人知道Linux中类似的东西,或者可以指导它在VxWorks或LynxOS中如何操作。

Any ideas??

有什么想法?

3 个解决方案

#1


6  

The function you seek in VxWorks is called vxMemProbe.

您在VxWorks中寻找的函数称为vxMemProbe。

Basically the vxMemProbe libraries insert special exception handling code to catch a page fault or bus error. The vxMemProbe function is used to check if the address is valid for read or write. It also allows you to test if the particular address is accessible with a given data width (8,16,32,64 bits) and alignment.

基本上,vxMemProbe库插入特殊的异常处理代码,以捕获页面错误或总线错误。vxMemProbe函数用于检查地址是否对读写有效。它还允许您测试特定的地址是否具有给定的数据宽度(8、16、32、64位)和对齐。

The underlying mechanism of vxMemProbe is tied to the specific architectures exception handling mechanisms. The vxMemProbe libraries insert code into the exception handlers. When you probe an address that triggers an exception the handler checks to see if vxMemProbe triggered the exception. If so, then the handler restores the state processor prior to the exception and returns execution to where vxMemProbe was called while also returning value via the architectures given calling conventions.

vxMemProbe的底层机制与特定的体系结构异常处理机制相关联。vxMemProbe库向异常处理程序插入代码。当您探测触发异常的地址时,处理程序将检查vxMemProbe是否触发该异常。如果是,那么处理程序将在异常之前恢复状态处理器,并返回调用vxMemProbe的执行,同时还通过给定调用约定的体系结构返回值。

#2


3  

In general you can't do what you want, as explained in Felix Palmen's answer.

一般来说,你不能做你想做的事情,正如费利克斯·帕尔曼在他的回答中解释的那样。

I should get a warning or error which says that In my application I cannot assign the address value to the integer.

我应该得到一个警告或错误,说明在我的应用程序中,我不能将地址值赋给这个整数。

Statically and reliably detecting all pointer faults is impossible (because it could be proven equivalent to solving the halting problem). BTW you might consider using static program analysis tools like Frama-C.

静态和可靠地检测所有指针故障是不可能的(因为它可以被证明等同于解决停机问题)。顺便说一句,您可以考虑使用诸如Frama-C这样的静态程序分析工具。

On Linux, in principle, you might test at runtime if a given address is valid in your virtual address space by e.g. using /proc/, e.g. by parsing the /proc/self/maps pseudo textual file (to understand what I mean try cat /proc/$$/maps in a terminal, then cat /proc/self/maps). See proc(5). In practice I don't recommend doing that often (it probably would be too slow), and of course it is not a builtin function of the compiler (you should code it yourself). BTW, be aware of ASLR.

在Linux上,原则上,如果给定的地址在您的虚拟地址空间中是有效的,您可以在运行时进行测试,例如使用/proc/,例如解析/proc/self/maps伪文本文件(要理解我的意思,请尝试在终端中使用cat /proc/self/maps)。看到proc(5)。在实践中,我不建议经常这样做(可能会太慢),当然它不是编译器的内置函数(您应该自己编写它)。顺便说一句,注意ASLR。

However, there are tools to help detect (some of) the faulty address uses, in particular valgrind and the address sanitizer facility, read about instrumentation options of GCC and try to compile with -fsanitize=address ...

但是,有一些工具可以帮助检测(一些)错误的地址使用,特别是valgrind和address sanitizer设施,读取GCC的检测选项并尝试使用-fsanitize=address…

Don't forget to compile your code with all warnings and debug info, so use gcc -Wall -Wextra -g to compile it.

不要忘记用所有的警告和调试信息编译代码,所以使用gcc -Wall -Wextra -g编译它。

BTW, if you store in some global pointer the address of some local variable and dereference that pointer after that local variable is in scope, you still have some undefined behavior (even if your code don't crash, because you usually dereference some random address on your call stack) and you should be very scared. UB should be always avoided.

顺便说一句,如果你存储在一些全球指针地址指针的一些局部变量和废弃,局部变量范围后,你仍然有一些未定义的行为(即使你的代码不崩溃,因为你通常废弃一些随机地址调用堆栈),你应该非常害怕。应该避免使用UB。

#3


3  

There are several misconceptions here:

这里有几个误解:

  • From the perspective of the language C, there's only one pointer value that's guaranteed to be invalid, and this is NULL. For other values, it depends on the context. A pointer is valid when it points to an object that is currently alive. (Note that this is trivially true in your int *i = &variable example, as this is only valid syntax when there is a variable accessible from your current scope)

    从语言C的角度来看,只有一个指针值是无效的,这个值是空的。对于其他值,它取决于上下文。指针指向当前活动的对象时是有效的。(注意,在您的int *i = &variable示例中,这是非常正确的,因为只有当您当前范围中有一个可访问的变量时,这才是有效的语法)

  • NULL does not necessarily mean a value with all bits zero. This is the most common case, but there can be platforms that use a different bit pattern for the NULL pointer. It's even allowed by the C standard that pointers of different types have different representations for NULL. Still, converting 0 to a pointer type is guaranteed to result in the NULL pointer for this type.

    NULL并不一定意味着值为零。这是最常见的情况,但是对于空指针可以使用不同的位模式。它甚至被C标准所允许,不同类型的指针对NULL有不同的表示。不过,将0转换为指针类型仍然保证会导致该类型的空指针。

  • I don't know what exactly you're referring to in VxWorks, but of course Linux checks memory accesses. If a process tries to access an address that's not mapped in the virtual address space, this process is sent a SIGSEGV signal, which causes immediate abnormal program termination (Segmentation fault).

    我不知道您在VxWorks中确切指的是什么,但是当然Linux检查内存访问。如果进程试图访问虚拟地址空间中没有映射的地址,则此进程将发送一个SIGSEGV信号,这将立即导致程序异常终止(分段错误)。

#1


6  

The function you seek in VxWorks is called vxMemProbe.

您在VxWorks中寻找的函数称为vxMemProbe。

Basically the vxMemProbe libraries insert special exception handling code to catch a page fault or bus error. The vxMemProbe function is used to check if the address is valid for read or write. It also allows you to test if the particular address is accessible with a given data width (8,16,32,64 bits) and alignment.

基本上,vxMemProbe库插入特殊的异常处理代码,以捕获页面错误或总线错误。vxMemProbe函数用于检查地址是否对读写有效。它还允许您测试特定的地址是否具有给定的数据宽度(8、16、32、64位)和对齐。

The underlying mechanism of vxMemProbe is tied to the specific architectures exception handling mechanisms. The vxMemProbe libraries insert code into the exception handlers. When you probe an address that triggers an exception the handler checks to see if vxMemProbe triggered the exception. If so, then the handler restores the state processor prior to the exception and returns execution to where vxMemProbe was called while also returning value via the architectures given calling conventions.

vxMemProbe的底层机制与特定的体系结构异常处理机制相关联。vxMemProbe库向异常处理程序插入代码。当您探测触发异常的地址时,处理程序将检查vxMemProbe是否触发该异常。如果是,那么处理程序将在异常之前恢复状态处理器,并返回调用vxMemProbe的执行,同时还通过给定调用约定的体系结构返回值。

#2


3  

In general you can't do what you want, as explained in Felix Palmen's answer.

一般来说,你不能做你想做的事情,正如费利克斯·帕尔曼在他的回答中解释的那样。

I should get a warning or error which says that In my application I cannot assign the address value to the integer.

我应该得到一个警告或错误,说明在我的应用程序中,我不能将地址值赋给这个整数。

Statically and reliably detecting all pointer faults is impossible (because it could be proven equivalent to solving the halting problem). BTW you might consider using static program analysis tools like Frama-C.

静态和可靠地检测所有指针故障是不可能的(因为它可以被证明等同于解决停机问题)。顺便说一句,您可以考虑使用诸如Frama-C这样的静态程序分析工具。

On Linux, in principle, you might test at runtime if a given address is valid in your virtual address space by e.g. using /proc/, e.g. by parsing the /proc/self/maps pseudo textual file (to understand what I mean try cat /proc/$$/maps in a terminal, then cat /proc/self/maps). See proc(5). In practice I don't recommend doing that often (it probably would be too slow), and of course it is not a builtin function of the compiler (you should code it yourself). BTW, be aware of ASLR.

在Linux上,原则上,如果给定的地址在您的虚拟地址空间中是有效的,您可以在运行时进行测试,例如使用/proc/,例如解析/proc/self/maps伪文本文件(要理解我的意思,请尝试在终端中使用cat /proc/self/maps)。看到proc(5)。在实践中,我不建议经常这样做(可能会太慢),当然它不是编译器的内置函数(您应该自己编写它)。顺便说一句,注意ASLR。

However, there are tools to help detect (some of) the faulty address uses, in particular valgrind and the address sanitizer facility, read about instrumentation options of GCC and try to compile with -fsanitize=address ...

但是,有一些工具可以帮助检测(一些)错误的地址使用,特别是valgrind和address sanitizer设施,读取GCC的检测选项并尝试使用-fsanitize=address…

Don't forget to compile your code with all warnings and debug info, so use gcc -Wall -Wextra -g to compile it.

不要忘记用所有的警告和调试信息编译代码,所以使用gcc -Wall -Wextra -g编译它。

BTW, if you store in some global pointer the address of some local variable and dereference that pointer after that local variable is in scope, you still have some undefined behavior (even if your code don't crash, because you usually dereference some random address on your call stack) and you should be very scared. UB should be always avoided.

顺便说一句,如果你存储在一些全球指针地址指针的一些局部变量和废弃,局部变量范围后,你仍然有一些未定义的行为(即使你的代码不崩溃,因为你通常废弃一些随机地址调用堆栈),你应该非常害怕。应该避免使用UB。

#3


3  

There are several misconceptions here:

这里有几个误解:

  • From the perspective of the language C, there's only one pointer value that's guaranteed to be invalid, and this is NULL. For other values, it depends on the context. A pointer is valid when it points to an object that is currently alive. (Note that this is trivially true in your int *i = &variable example, as this is only valid syntax when there is a variable accessible from your current scope)

    从语言C的角度来看,只有一个指针值是无效的,这个值是空的。对于其他值,它取决于上下文。指针指向当前活动的对象时是有效的。(注意,在您的int *i = &variable示例中,这是非常正确的,因为只有当您当前范围中有一个可访问的变量时,这才是有效的语法)

  • NULL does not necessarily mean a value with all bits zero. This is the most common case, but there can be platforms that use a different bit pattern for the NULL pointer. It's even allowed by the C standard that pointers of different types have different representations for NULL. Still, converting 0 to a pointer type is guaranteed to result in the NULL pointer for this type.

    NULL并不一定意味着值为零。这是最常见的情况,但是对于空指针可以使用不同的位模式。它甚至被C标准所允许,不同类型的指针对NULL有不同的表示。不过,将0转换为指针类型仍然保证会导致该类型的空指针。

  • I don't know what exactly you're referring to in VxWorks, but of course Linux checks memory accesses. If a process tries to access an address that's not mapped in the virtual address space, this process is sent a SIGSEGV signal, which causes immediate abnormal program termination (Segmentation fault).

    我不知道您在VxWorks中确切指的是什么,但是当然Linux检查内存访问。如果进程试图访问虚拟地址空间中没有映射的地址,则此进程将发送一个SIGSEGV信号,这将立即导致程序异常终止(分段错误)。