“安全”指针值间隔?

时间:2011-07-18 19:41:24

标签: c++ c pointers

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

在很多程序中,我看到指针都会检查NULL。但这并不妨碍传递像0x002011这样的疯狂地址。

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

12 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:3)

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

答案 2 :(得分:2)

来自NULL和朋友的除malloc之外的所有内容都是一个有效的指针,无论它看起来多么疯狂。实际上,0x002011可能是某些计算机上完全有效的指针(尽管可能不是现代桌面)。

还有很多关于正确对齐,“看上去很好”的地址的指针仍然不属于您的程序。如果您未将指针保留为未初始化且未手动将它们设置为废话值,那么您必须注意的唯一无效指针是NULL。或者,如果这是用于库代码:不要尝试为您的用户执行此操作,因为您不能(如果上述内容不够明确),并且无论如何这都是他们的工作。

答案 3 :(得分:2)

还有另一个案例没有在这里解决:编写一个库函数,你无法控制传入的参数,你想确保你的函数返回一个“坏指针”类型的错误而不是崩溃如果使用指向无效地址的指针。

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

请注意,即使您采取这些预防措施,仍然无法保证调用者不会将合法指针传递给无效数据。最重要的是,您无法修复调用代码中的错误。

答案 4 :(得分:1)

不,没有(便携和可靠的)方法来检测指针是否良好。

答案 5 :(得分:1)

不,这不是正确的做事方式。

你应该找出为什么这些疯狂的地址首先被传递。您应该始终传递一个您使用new或malloc(或其中某些变体)的有效指针来创建,或者您应该传递堆栈分配对象的地址。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

不,没有。如果可能,请使用始终指向有效内存的引用。指针本质上是危险的,这就是Java等高级语言完全省略它们的原因。

实际上,即使NULL也不能保证指向无效的内存。这只是一个举行会议,但没有任何标准AFAIK支持。

答案 8 :(得分:0)

正如其他人所说,没有办法。

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

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

尽管如此,这些和其他“推理”并不可靠(也不便携)。

答案 9 :(得分:0)

不,这就是检查指针反对NULL的原因,除非你有定义并记录一个函数接受NULL并赋予它一个特殊含义,这是完全没有意义的。 C不能编写接受指针的函数,但是对于打破合同的调用者来说是强大的。如果您不喜欢这样,请不要使用指针或不使用C.

答案 10 :(得分:0)

在Windows中,您可以尝试使用VirtualQuery功能。它接受您要测试的指针( lpAddress )并返回有关包含该地址的页面的信息(如果它是有效的。)

  

如果 lpAddress 指定了进程可访问的最高内存地址之上的地址,则该函数将失败并显示ERROR_INVALID_PARAMETER。

这个问题可能会给你一些关于Linux的起点:Is there a better way than parsing /proc/self/maps to figure out memory protection?

答案 11 :(得分:0)

不,对于指针,除零之外的任何值都可以是有效地址。因此传统上程序员已经使用过 NULL作为指针的默认 invlaid值。

但是,如果您正在开发需要此工具的库,那么您可以使用以下其中一个

  1. 在开头分配库所需的内存。 (假设您事先知道要求)。 使用自定义内存管理器,它将使用此内存块来为内存分配和库的空闲请求提供服务。任何超出分配内存的地址({起始地址,开始地址+大小})都是无效指针。
  2. OR

    1. 开发自定义内存管理器,它跟踪分配给库的不同模块的内存块。要检查指针的有效性,它会通过其内部表来查看是否已分配了这样的内存。
    2. 注意: 如果性能问题,那么您可以让内存管理器以两种模式运行,即发布和调试。查看发布版本中的附加检查。

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

      Shash316