64位系统中的程序崩溃
Program Crashes in 64 bit System
以下代码在64位系统中崩溃。如果文件名长度小于3,'len'
发生下溢。但是这个程序没有显示任何32位系统的分段故障。但我得到分割错误在64位系统。为什么这个程序不显示任何分割错误在32位系统?
DIR * dirp = opendir(dirPath);
struct dirent * dp;
while(dirp)
{
if((dp = readdir(dirp)) != NULL)
{
unsigned int len = strlen(dp->d_name);
//underflow happens if filename length less than 3
if((dp->d_name[len - 3] == 'j'))
}
}
您的程序导致未定义的行为,正如您似乎意识到的那样。您正在尝试访问数组的边界之外。未定义行为就像它听起来的那样。行为没有定义。任何事情都有可能发生。
你可能会得到一个分割错误一次你运行,而不是另一次。或者您可能在不同的编译器下看到不同的行为。未定义行为本质上是不可预测的。事实上,您似乎在一个编译器下摆脱了代码中的这个错误,但这并不能使您的代码正确。
显然,你应该做的是避免编写导致未定义行为的程序。
为什么这个程序在32位系统中没有显示任何分割错误?
看,这是稍微简化了你的程序:
1 int main(int argc, char *argv[])
2 {
3 char name[100];
4 unsigned int len = 3;
5 name[len-argc] = 1;
6 return 0;
7 }
因此,当我将其构建为32位程序gcc -m32 -g main.c -o main32
时,gdb下进程的地址空间是这样的:
$ gdb -q --args ./main32 1 2 3
Reading symbols from /home/main32...done.
(gdb) start
(gdb) info proc mappings
process 28330
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x110000 0x111000 0x1000 0x0 [vdso]
0x3fa000 0x418000 0x1e000 0x0 /lib/ld-2.12.so
0x418000 0x419000 0x1000 0x1d000 /lib/ld-2.12.so
0x419000 0x41a000 0x1000 0x1e000 /lib/ld-2.12.so
0x41c000 0x5a8000 0x18c000 0x0 /lib/libc-2.12.so
0x5a8000 0x5aa000 0x2000 0x18c000 /lib/libc-2.12.so
0x5aa000 0x5ab000 0x1000 0x18e000 /lib/libc-2.12.so
0x5ab000 0x5ae000 0x3000 0x0
0x8048000 0x8049000 0x1000 0x0 /home/main32
0x8049000 0x804a000 0x1000 0x0 /home/main32
0xf7fdf000 0xf7fe0000 0x1000 0x0
0xf7ffd000 0xf7ffe000 0x1000 0x0
0xfffe9000 0xffffe000 0x15000 0x0 [stack]
(gdb) p/x &(name[len-argc])
$2 = 0xffffcfab
你可以看到name[3-4]
(它是underflow
,你说)实际上指向堆栈上的一个有效地址。这就是为什么你的进程不会崩溃。
当我构建与64位(gcc -m64 -g main.c -o main64
)相同的程序时,地址将无效
(gdb) info proc mappings
process 29253
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /home/main64
0x600000 0x601000 0x1000 0x0 /home/main64
0x3c40a00000 0x3c40a20000 0x20000 0x0 /lib64/ld-2.12.so
0x3c40c1f000 0x3c40c20000 0x1000 0x1f000 /lib64/ld-2.12.so
0x3c40c20000 0x3c40c21000 0x1000 0x20000 /lib64/ld-2.12.so
0x3c40c21000 0x3c40c22000 0x1000 0x0
0x3c41200000 0x3c41389000 0x189000 0x0 /lib64/libc-2.12.so
0x3c41389000 0x3c41588000 0x1ff000 0x189000 /lib64/libc-2.12.so
0x3c41588000 0x3c4158c000 0x4000 0x188000 /lib64/libc-2.12.so
0x3c4158c000 0x3c4158d000 0x1000 0x18c000 /lib64/libc-2.12.so
0x3c4158d000 0x3c41592000 0x5000 0x0
0x7ffff7fdd000 0x7ffff7fe0000 0x3000 0x0
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x0
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0 [vdso]
0x7ffffffea000 0x7ffffffff000 0x15000 0x0 [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
(gdb) p/x &name[len-argc]
$5 = 0x8000ffffde3f
还有一点。以下是64位应用程序的汇编程序:
(gdb) disassemble /m
Dump of assembler code for function main:
5 name[len-argc] = 1;
0x0000000000400472 <+22>: mov -0x74(%rbp),%edx
0x0000000000400475 <+25>: mov -0x4(%rbp),%eax
0x0000000000400478 <+28>: sub %edx,%eax
0x000000000040047a <+30>: mov %eax,%eax
=> 0x000000000040047c <+32>: movb $0x1,-0x70(%rbp,%rax,1)
这是$eax::
(gdb) p $eax
$1 = -1
但分配使用rax
,因为你是在64模式。这是$rax:
(gdb) p/x $rax
$3 = 0xffffffff
所以程序在一个有效的堆栈地址上增加了一个巨大的正偏移量,结果是无效的地址。
我想强调一下这在32和64模式下都是未定义的行为。如果你想修复这个未定义的行为,你可以阅读我的另一个答案https://stackoverflow.com/a/24287919/184968.
dp->d_name[len - 3] == 'j'
len - 3
可能在32位机器的段内,而在64位机器的段外。这和你的操作系统有关。
- 程序崩溃并显示"std::out_of_range"错误
- 试图创建流或fopen时程序崩溃
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- 如何找出应用程序崩溃的原因 - Win 10 LTSB
- 操纵安卓相机的深度图导致应用程序崩溃
- 为什么当我尝试搜索双链表中第一个数据条目之外的数据时,程序崩溃了?
- DLL Made with CMake 使程序崩溃
- 程序崩溃使用boost::asio
- 调用 free() 有时会导致程序崩溃
- 邮件加密程序崩溃
- 调用 java 的回调() 时应用程序崩溃.由于 detatchThread 而获得运行时错误
- 比较迭代器会使程序崩溃,而不会在自定义气泡排序实现中出现错误
- For 循环在尝试读取数组 c++ 时程序崩溃
- 即使有 0 个错误,Getter 似乎也会使程序崩溃
- Windows桌面程序保存您的计算机会话 - 基于程序崩溃时的恢复会话
- 无法访问的代码如何导致我的程序崩溃?
- 矢量迭代器在尝试调用函数时使我的程序崩溃
- QCompleter set模型使应用程序崩溃
- 使用唯一指针调用函数会使我的程序崩溃
- 删除SDL_PollEvent时程序崩溃