分段故障-为什么以及如何工作
Segmentation fault - why and how does it work?
在下面定义的两个函数中,它都试图在堆栈中分配10M内存。但是分割错误只发生在第二种情况下,而不是第一种情况,我正在努力理解为什么会这样
函数定义1:
a(int *i)
{
char iptr[50000000];
*i = 1;
}
函数定义2:
a()
{
char c;
char iptr[5000000];
printf("&c = 0x%lx, iptr = 0x%x ... ", &c, iptr);
fflush(stdout);
c = iptr[0];
printf("okn");
}
根据我的理解,在局部变量没有动态分配内存的情况下,这些变量存储在程序的堆栈部分。所以我想,在编译时,编译器会检查变量是否适合堆栈。
因此,如果上述是真的,那么在这两种情况下(即,在情况1中)都应该发生分段故障。
网站(http://web.eecs.utk.edu/courses/spring2012/cs360/360/notes/Memory/lecture.html)从我选择的地方可以看出,当代码试图在堆栈上为printf调用推送iptr时,segfault发生在a中的函数2中。这是因为堆栈指针指向的是空白 如果我们没有在堆栈指针处引用任何内容,我们的程序应该已经工作了
我需要帮助理解最后的发言以及我之前对此的怀疑。
所以我想,在编译时,编译器会检查变量是否适合堆栈。
不,那是不可能的。编译函数时,编译器不知道调用函数时的调用堆栈是什么,因此它会假设您知道自己在做什么(可能是这样,也可能不是这样)。还要注意,堆栈空间的大小可能会受到编译时间和运行时限制的影响(在Linux中,您可以在启动进程的shell上使用ulimit
设置堆栈大小)。
我需要帮助理解最后的发言以及我之前对此的怀疑。
我不会试图过多地研究该声明,它不是标准,而是基于对特定实现的了解,而这些知识甚至没有在其中描述,因此是建立在一些不一定正确的假设之上的。
它假设分配数组的行为不会"接触"分配的内存(在某些调试构建中,在某些实现中,这是错误的),因此,无论您试图分配1字节还是100M,如果您的程序没有接触到数据,分配都是好——事实并非如此。
它还假设函数printf
的参数是在堆栈中传递的(由于函数的变参数性质,在我所知道的所有实现中都是这种情况)。根据前面的假设,数组会溢出堆栈(假设堆栈<10M),但不会因为内存未被访问而崩溃,但为了能够调用printf
,参数的值将被推送到数组之外的堆栈。这将向内存写入,并且写入将超出为堆栈和崩溃分配的空间。
同样,所有这些都是实现,而不是由语言定义的。
以下代码引发代码错误:
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page. "**This line throws the error**"
jmp short cs10
_chkstk endp
end
来自chkstk.asm文件,该文件提供对过程条目的堆栈检查。这个文件明确定义了:
_PAGESIZE_ equ 1000h
现在作为你的问题的解释,这个问题告诉你所需要的一切,如Shafik Yaghmour
您的printf
格式字符串假定指针、int(%x
)和long(%lx
)的大小都相同;这在您的平台上可能是错误的,从而导致未定义的行为。请改用%p
。我本想对此发表评论,但现在还不能。
我很惊讶没有人注意到第一个函数分配的空间是第二个函数的10倍。在第一个函数中,5之后有7个零,而第二个函数在5:-之后有6个零。)
我用gcc-4.6.3编译了它,在第一个函数上出现了分段错误,但在第二个函数上没有。在我删除了第一个函数中的额外零之后,seg故障就消失了。在第二个函数中添加一个零引入了seg故障。所以,至少在我的情况下,这个seg错误的原因是程序无法在堆栈上分配所需的空间。我很高兴听到与上述不同的意见。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?