[英]Tiny crashing program
以下程序使用g ++编译,但是在运行时崩溃:
class someClass
{
public:
int const mem;
someClass(int arg):mem(arg){}
};
int main()
{
int arg = 0;
someClass ob(arg);
float* sample;
*sample = (float)1;
return 0;
}
以下程序不会崩溃:
int main()
{
float* sample;
*sample = (float)1;
return 0;
}
float* sample;
*sample = (float)1;
sample
从未初始化为指向对象,因此,当您取消引用它时,程序将崩溃。 您需要先对其进行初始化,然后再使用它,例如:
float f;
float* sample = &f;
*sample = (float)1;
即使您的第二个程序没有崩溃,它仍然是错误的。 取消引用未指向有效对象的指针会导致未定义的行为。 结果可能是您的程序崩溃,内存中的某些其他数据被覆盖,您的应用程序似乎继续正常运行或任何其他结果。 您的程序今天看起来运行良好,但明天运行时崩溃。
经过一番思考,我可以肯定地告诉您为什么第二个示例没有崩溃。
执行程序时,crt(c运行时)将3个值压入堆栈:参数数量( int
),参数为char **
和环境字符串也为char **
,然后调用main
。
现在,当您编写main
函数时,据我所知,它总是读取前两个值,并将它们传递给函数的参数(如果有)。 如果包含第3个参数,则它也会传递第3个值,否则它将保留在堆栈中。 因此,程序开始时的堆栈如下所示:
+--------+
| # args |
+--------+
| args |
+--------+ <------ stack pointer
| envs |
+--------+
在第一个示例中,您在堆栈上分配了int
和struct,然后是指针,因此第一个示例中的完整堆栈如下所示:
+--------+
| # args |
+--------+
| args |
+--------+ <------ stack pointer
| arg | <------ your integer, initialized in code
+--------+
| ob | <------ your struct, initialized in code
+--------+
| sample | <------ your pointer, uninitalized = garbage
+--------+
因此, sample
是纯垃圾,尝试取消引用它会使您的程序崩溃。
现在在第二个示例中,堆栈如下所示:
+--------+
| # args |
+--------+
| args |
+--------+ <------ stack pointer
| sample | <------ pointer, uninitalized (!)
+--------+
指针仍然是未初始化的,但是它改写的值是envp
,它是指向数组的实际指针: char **
。 取消引用它时,您将返回一个“指向char的指针”数组,因此可以安全地覆盖它(只要您不再尝试将其视为原始指针)。 内存已分配,您可以使用它。
现在,这当然是特定于实现的,但是似乎适合您的编译器,对吗? 您可以通过gdb
检查(char**)sample
确实指向环境变量数组,然后再覆盖它。
MSVC ++ 10中的屏幕快照,处于32位发布模式下(调试模式会强制初始化所有变量,以防止发生这种情况):
实际使用中的指针http://img651.imageshack.us/img651/5918/69916340.png
取消引用未初始化的指针: http : //www.cprogramming.com/debugging/segfaults.html
您正在取消引用统一指针。
真正有趣的是,为什么第二个示例不会对您造成崩溃,因为它具有相同的问题
顺便说一句:对我来说(gcc 4.4,amd64)都崩溃了。
如果您真的对第二个示例为何不会崩溃感到兴趣,请使用调试信息进行编译,然后在调试器中启动它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.