程序在64位系统中崩溃

时间:2014-06-24 11:08:09

标签: c++ c gdb

以下代码在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'))
    }
  }

3 个答案:

答案 0 :(得分:5)

您可能会看到未定义的行为。您试图访问数组边界之外。并且未定义的行为正是听起来的样子。行为未定义。什么事情都可能发生。

一旦运行,您可能会遇到分段错误,而不是另一次。或者您可能会在不同的编译器下看到不同的行为。未定义的行为本质上是不可预测的。你似乎在一个编译器下的代码中逃脱了这个错误的事实并没有使你的代码正确。

显然,你应该做的是避免编写导致未定义行为的程序。

答案 1 :(得分:4)

  

为什么这个程序在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

但是,因为您处于64模式,所以指定使用rax。这是$ rax:

的价值
(gdb) p/x $rax
$3 = 0xffffffff

因此,程序会向有效堆栈添加一个巨大的正偏移量,并导致无效的地址。

我想强调这是32和64模式下的未定义行为。如果您想修复此未定义的行为,您可以阅读我的另一个答案https://stackoverflow.com/a/24287919/184968

答案 2 :(得分:1)

dp->d_name[len - 3] == 'j' len - 3可能位于此32位计算机上的细分市场中,位于64位计算机上的细分市场之外。它与您的操作系统有关。