"安全"指针值间隔?

"Safe" pointer values interval?

本文关键字:安全 指针      更新时间:2023-10-16

首先,我对堆栈和堆不是很熟悉。

在许多程序中,我看到指针检查NULL。但这并不能阻止像0x002011这样疯狂的地址被传递。

我的问题:是否有"安全"的地址间隔,我可以检查指针属于并合理确定它是有效的,在解引用之前?

确保在创建新变量时将指针初始化为NULL,然后仅使用malloc(当C时)或new(当c++时)或其他分配函数(或分配给另一个有效指针或NULL)更改值。分别在freedelete之后设置为NULL。

NULL是一个特殊的值,保证是一个无效的指针。任何其他值都可以是有效的。

这里还没有解决另一种情况:编写一个库函数,您无法控制传入的参数,并且您希望确保函数返回"坏指针"类型的错误,而不是在使用指向无效地址的指针时崩溃。

如果是这样的话,那么我认为有特定于操作系统的函数可以给你当前进程的有效地址范围。您还需要考虑地址的对齐方式对于传递的数据类型是否有效。例如,如果一个4字节整数值可以合法地驻留在一个奇数地址,其中地址%4 != 0.

注意,即使你采取了这些预防措施,仍然不能保证调用者不会传递一个指向无效数据的合法指针。底线是,您无法修复调用代码中的错误。

malloc和friends中除了NULL之外的所有内容都是有效的指针,无论它的值对您来说多么疯狂。事实上,0x002011在某些计算机上可能是一个完全有效的指针(尽管可能不是现代桌面)。

还有一大堆指针指向正确对齐的、"看起来很正常"的地址,这些地址仍然不属于你的程序。如果指针没有初始化,也没有手动设置它们的值,那么唯一需要注意的无效指针是NULL。或者,如果这是针对库代码:不要尝试为用户这样做,因为你不能(如果上面的代码不够明确),而且这是他们的工作。

不,没有一种(可移植和可靠的)方法来检测指针是否好。

不,那不是正确的做法。

你应该首先弄清楚为什么要传递这些疯狂的地址。您应该总是传递一个使用new或malloc(或它们的一些变体)创建的有效指针,或者您应该传递堆栈分配对象的地址。

指针是一个实现细节,而不是上下文类型。因此,"有效指针值"不是指针的通用属性;它是使用指针的上下文(或指针所表示的抽象)的属性。例如,指向线程堆栈上某个东西的指针不是传递给free(...)的有效指针。如果您可以表示指针有效的上下文,那么只需枚举或匹配该上下文中所有有效的指针,以确定指针是否有效(同样,在该上下文中)。

没有。如果可能的话,使用应该始终指向有效内存的引用。从本质上讲,指针是危险的,这就是为什么像Java这样的高级语言完全省略了它们。

实际上,甚至NULL也不能保证指向无效内存。这只是一种惯例,没有任何标准的支持。

不可能,就像别人说的。

但是如果有一种方法可以知道哪些地址在进程的地址空间中,那么你可以有一个线索(如果地址在"内部",它不一定是一个好的有效指针;但如果它在外部,则肯定是无效的)。

一些可能的检查是系统相关的(前面的句子也确实假设了一组特定的现代系统);例如,在许多机器上地址必须是字对齐或类似的,所以如果你有一个奇数地址(对于一个非字节的数据),你可以认为它不是一个有效的指针。

然而,这些和其他的"推理"是不可靠的(也不能移植)。

不,这就是为什么检查指针是否为NULL是完全没有意义的,除非你已经定义并记录了一个函数接受NULL并赋予它一个特殊的含义。C不允许编写接受指针但对调用者破坏契约具有鲁棒性的函数。如果你不喜欢这样,要么不要使用指针,要么不要使用c。

在Windows中,你可以尝试使用VirtualQuery函数。它接受要测试的指针(lpAddress),并返回包含地址的页面的信息,如果它是一个有效的地址。

如果lpAddress指定的地址高于进程可访问的最高内存地址,则函数失败并返回ERROR_INVALID_PARAMETER。

这个问题可能会给你一些Linux上的起点:有没有比解析/proc/self/maps更好的方法来计算内存保护?

不可以,对于指针,除了0以外的任何值都可以是有效地址。因此,传统上程序员使用NULL作为指针的默认嵌入值。

但是,如果您正在开发一个需要此功能的库,则可以使用以下命令之一

  1. 分配库在开始时所需的内存。(假设你事先知道要求)。使用自定义内存管理器,它将使用该内存块来服务内存分配和释放库的请求。任何超出分配内存的地址({起始地址,起始地址+大小})都是无效指针。

  1. 开发自定义内存管理器,跟踪分配给库不同模块的内存块。为了检查指针的有效性,它会遍历它的内部表,看看是否分配了这样的内存。

注意:如果性能是问题,那么你可以让内存管理器在两种模式下运行,即发布和调试。在发布版本中删除额外的检查

Opencore(在Android中)与第二种方法类似。

Shash316