【问题标题】:How can I identify an invalid memory address?如何识别无效的内存地址?
【发布时间】:2014-09-15 06:08:57
【问题描述】:

我想知道是否有某种方法可以识别特定平台上的无效内存地址(x86 64 位,就我而言)。我需要它在程序取消引用地址并引发 SIGILL/SIGSEGV 错误之前捕获它。

【问题讨论】:

  • 您可以使用 valgrind 来帮助追踪这类东西,这不仅会捕获明显的无效取消引用,而且通常会捕获更微妙的取消引用,例如 off-by-one 等。
  • 不能修复访问无效内存位置的代码吗?
  • 也许不能再使用后马上设置为NULL?
  • 我在下面暗示了这一点,但这听起来非常像an X-Y problem。如果您可以举例说明为什么您需要检查地址是否有效,而不是将您的程序设计为确定它是有效的,这可能会有所帮助。
  • 我问这个问题是因为 valgrind 无法使用,因为产品和运行它的测试用例太大了。我想我应该清楚地提到这一点!

标签: c linux memory


【解决方案1】:

一般来说,你不能。无效地址看起来与有效地址大致相同。唯一可识别的无效地址是NULL

因此,在使用它们之前,请确保(这样编写您的代码)您的指针是有效的或NULL总是。没有办法解决这个问题。

您可以使用工具来检测您的指针可能无效的位置(例如,未初始化、已释放等),但这不是您要问的。

【讨论】:

  • 我对 Linux 了解不多,但肯定至少有一种方法可以确定给定进程可以访问哪些地址空间?这样您至少可以确定指针对于本地 .stack .data 或 .bss 段是否有效?
  • 是的,这可能是可能的,虽然它不是那么容易,因为它不必是一个连续的内存块。但即使你能找出来,那仍然不能保证你的指针是有效的。它可以是指向先前释放(甚至可能重新使用)的内存块的指针。这当然指向你的地址空间,或者你当前的堆栈帧,或者其他什么,但它仍然是无效的。
【解决方案2】:

你可以在文件/proc/self/maps中看到当前进程的所有内存映射。只需打开该文件并处理其内容:每行以两个由- 分隔的十六进制数字开头,这是进程可以访问的地址。

你的进程映射的所有内存地址都在那里,但其中一些可能没有读、写或执行权限;如果您需要检查它们,您还必须读取并解析下一个字段。

该文件的示例内容:

$ cat /proc/self/maps
00400000-0040c000 r-xp 00000000 08:01 24340229                           /bin/cat
0060b000-0060c000 r--p 0000b000 08:01 24340229                           /bin/cat
0060c000-0060d000 rw-p 0000c000 08:01 24340229                           /bin/cat
0253e000-0255f000 rw-p 00000000 00:00 0                                  [heap]
[...]
7f050d97e000-7f050d97f000 rw-p 00000000 00:00 0 
7fff9509e000-7fff950bf000 rw-p 00000000 00:00 0                          [stack]
7fff951fe000-7fff95200000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

【讨论】:

    【解决方案3】:

    您可以使用mincore 函数。见描述here

    如果地址没有映射到进程虚拟地址空间,mincore会返回错误。

    这不是 100%,因为内存可以映射到进程虚拟地址空间但未提交(未分配物理页面)。如果不是全部,它将捕获大部分垃圾指针。

    您可以在here 中阅读有关使用mmap 函数的内存映射的更多信息

    【讨论】:

      【解决方案4】:

      如果专门防止SIGSEGV 是您的目标,请记住您可以使用signal 捕获段错误。您无需等待在使用点执行此操作(可能为时已晚) - 您可以暂时重新定义 SIGSEGV 处理程序,通过一个简单的身份例程运行您想要检查的所有地址(阅读目标值,将其写回),然后 - 如果您的处理程序从未检测到任何错误 - 恢复原始处理程序并继续您的代码部分,该部分需要知道它收到的所有地址都是安全(“安全”)以取消引用。如果没有,您可以向调用者提出或返回您自己的错误。

      但是,您通常无法判断地址是否真正有效,因为底层系统可能会围绕您使用 malloc 请求的实际对象分配一些东西,并且访问这些区域可能不会导致程序崩溃——就读取内存的行为而言,这些地址实际上也是“有效的”,即使它们不代表 C 对象。但是,如果您需要做的只是例如验证读取外部提供的缓冲区不会使您的代码崩溃,这不是您需要克服的障碍。

      【讨论】:

        猜你喜欢
        • 2012-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-22
        • 1970-01-01
        • 1970-01-01
        • 2015-04-23
        • 1970-01-01
        相关资源
        最近更新 更多