【问题标题】:Can C language decide if a memory pointed by pointer can be accessed?C语言可以决定是否可以访问指针指向的内存吗?
【发布时间】:2015-12-12 15:41:19
【问题描述】:

示例。

如果我有指针,

int* p;
p = (int*)2; // just for test
*p = 3; // it will be crack, right?

一般情况下,访问值为2的指针会被破解。但实际上破解并不是那么简单。指针的无效值可能来自运行时错误。我想找到一种在访问指针之前检查指针的方法。

【问题讨论】:

  • 没有办法检查指针在C中是否有效。访问无效内存也不能保证抛出错误。

标签: c pointers


【解决方案1】:

在标准 C99 中,此(在您的 *p =3; 语句中取消引用 (int*)2)是 undefined behavior (UB)。阅读C.Lattner's blog。你应该be very scared of UB。这就是 C 语言编程如此困难的原因(其他编程语言,如 Ocaml、Common Lisp 的 UB 少得多)。

C 程序可能有未定义的行为,但可能不会总是崩溃。

在实践中,在 C 中编码时,请注意指针。显式初始化所有这些(通常为NULL)。对指针运算要非常小心。避免使用buffer overflowsmemory leaksStatic source code analysis 可能会有所帮助(例如使用 Frama-C)但有限(请阅读 halting problemRice's theorem)。您可以经常使用flexible array members 并在运行时检查指针和索引。

在一些嵌入式独立 C 实现(例如,为类似设备的 Arduino 编码)中,某些地址可能具有特定含义(例如,一些物理 IO 设备),因此 UB 可能非常可怕。

(我下面重点讲Linux)

在某些实现和某些操作系统上,您可能会测试地址是否有效。例如,在 Linux 上,您可能会解析 /proc/self/maps 以计算某个给定地址是否有效(有关 /proc/ 的更多信息,请参阅 proc(5))。

(因此,您可以在 Linux 上编写一些函数 bool isreadableaddress(void*),它将解析 /proc/self/maps 并判断您的 processvirtual address space 中的地址是否可读;但它不会效率很高,因为需要几个system calls)

您应该使用valgrind 并使用所有警告和调试选项 (gcc -Wall -Wextra -g) 进行编译,并使用调试器 (gdb) 和更多 debugging compiler options,例如 -fsanitize=address

您可能会处理SIGSEGV 信号,但it非常棘手并且高度不可移植(操作系统、处理器和ABI 特定)。除非你是大师,否则你不应该尝试。

【讨论】:

  • 不过,OP 似乎在询问是否可以检查指针。
  • 请注意,在 Windows 上,有些功能似乎完全符合 OP 的要求(IsBadReadPtr 等)。不要使用它们:blogs.msdn.microsoft.com/oldnewthing/20060927-07/?p=29563(标题是“IsBadXXXPtr 真的应该被称为 CrashProgramRandomly”)。可能有人比那篇文章的作者更了解 Windows,但我不想赌它。每个 Windows 程序员都应该阅读这篇博客。
【解决方案2】:

是的,“它会裂开的”。

您的程序无法知道任意初始化的指针是否会在运行时实际“工作”。首先,在运行代码之前编译代码,可能在完全不同的计算机上。编译器无法预测未来。

语言通过说 any 指针没有明确地指向 您在程序中创建的对象或数组 不能存在,只要您希望您的程序具有明确定义的行为。

基本上,唯一确定的方法是不要这样做

【讨论】:

    【解决方案3】:

    其实有可能……有点……

    不是纯 C,但大多数环境允许您测试是否可以写入指针...

    for example

    很遗憾,您无法知道指针是否指向您的意图。这意味着您可能指向另一个有效地址,与您期望的不同,并且无意中破坏了您自己的一段记忆......

    char a[2];
    int b; // assuming they are stored on the stack sequentially and aligned one right after the other...
    
    char *ptr = (char*)a;
    
    ptr += 3;
    
    *ptr = 'b' // valid pointer, but probably an error....
    

    【讨论】:

    • 这如何回答取消引用 (int*)2 的问题?此外,Martin Bonner 评论(我的回答)并引用 blogs.msdn.microsoft.com/oldnewthing/20060927-07/?p=29563 这基本上不鼓励在 Windows 上使用 IsBadWritePtr...
    • 你看过他帖子的标题吗?他不关心(int*)2 ...这只是一个例子...我试图用简单的语言解释为什么他所要求的基本上是不可能的。
    • 在 Linux 上,可以(通过/proc/self/maps)判断给定地址是否可读。但你的论点适用。有效的地址可能不指向预期的东西。
    • 酷 :-) 。更多字符
    • *ptr = 'b' 不是有效指针。它可能会崩溃或不崩溃。例如a可能就在堆栈上的返回地址之前,如果你在valgrind下执行,它可能会停止程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    相关资源
    最近更新 更多