例.
如果我有一个指针,
int* p; p = (int*)2; // just for test *p = 3; // it will be crack, right?
通常,值2的指针的访问将是破解.但实际上裂缝并非如此简单.指针的无效值可能来自运行时错误.我想在访问之前找到一种检查指针的方法.
在标准C99中,这((int*)2
在您的*p =3;
语句中解除引用)是未定义的行为(UB).阅读C.Lattner的博客.你应该是很害怕 UB的.这就是为什么在C语言编程如此困难的原因(其他编程语言如Ocaml,Common Lisp的UB要少得多).
AC程序可能有未定义的行为,但可能并不总是崩溃.
在实践中,当用C编码时,要注意指针.明确地(通常是NULL
)初始化所有这些.指针算法要非常小心.避免缓冲区溢出和内存泄漏.静态源代码分析可能有所帮助(例如使用Frama-C)但有限(阅读关于暂停问题和赖斯定理).您可以经常使用灵活的数组成员,并在运行时检查指针和索引.
在一些嵌入式独立式C实现中(例如,对类似Arduino的设备进行编码),某些地址可能具有特定含义(例如,某些物理IO设备),因此UB可能非常可怕.
(我在下面关注Linux)
在某些实现和某些操作系统上,您可以测试地址是否有效.例如,在Linux上,您可能会解析/proc/self/maps
计算某个给定地址是否有效(有关详细信息,请参阅proc(5)/proc/
).
(因此,您可以在Linux上编写一些函数bool isreadableaddress(void*)
来解析/proc/self/maps
并判断一个地址在您的进程的虚拟地址空间中是否可读;但由于需要多次系统调用,因此效率不高)
你应该使用valgrind并编译所有警告和调试选项(gcc -Wall -Wextra -g
)并使用调试器(gdb
)和一些更多的调试编译器选项,如-fsanitize=address
你也许对这处理SIGSEGV
信号,但它是非常棘手和高度不可移植的(操作系统,处理器和ABI特定的).除非你是一个大师,否则你甚至不应该尝试.