繁体   English   中英

gdb的奇怪行为

[英]Strange behaviour of gdb

我正在调试gdb中的示例代码

#include <iostream>
#include <string.h>

using namespace std;

void c (char** q)
{
    q = new char*[2];
    if (q == NULL)
        cout<<"NO OK";
    else
        cout<<"OK";
}

int main ()
{
    char** d = NULL;
    c(d);
    return 1;
}

现在这个程序输出为“OK”,但在gdb中调试此代码时,我发现以下行为gdb -version GNU gdb(GDB)7.5.1

Breakpoint 1, c (q=0x0) at issue.cpp:8
warning: Source file is more recent than executable.
8           q = new char*[2];
(gdb) p q
$1 = (char **) 0x0
(gdb) n
9           if (q == NULL)
(gdb) p q
$2 = (char **) 0x0
(gdb) p q==0
$3 = true
(gdb) n
12              cout<<"OK";
(gdb) p q
$4 = (char **) 0x0
(gdb) p q==0
$5 = true
(gdb)     

gdb显示q值为null但代码执行方式不同。

嗯: warning: Source file is more recent than executable. - 这可能是你的答案。 尝试重新编译代码。

肯定会发生一些与gdb逻辑混淆的事情。 我在gcc 4.8.3中遇到你描述的行为,在cygwin (32位)中运行。

我在我的gdb会话中为您的代码获取此输出:

Breakpoint 1, main () at test.cpp:21
21          char** d = NULL;
(gdb) s
22          c(d);
(gdb) s
c (q=0x0) at test.cpp:9
9           q = new char*[2];
(gdb) s
13          if (q == NULL)
(gdb) p q
$1 = (char **) 0x0
(gdb) p &q
$2 = (char ***) 0x22abd0
(gdb) x 0x22abd0
0x22abd0:       0x00000000

现在如果我只是改变你的功能:

void c (char** q)
{
    cout << q << endl;
    q = new char*[2];
    if (q == NULL)
        cout<<"NO OK";
    else
        cout<<"OK";
}

gdb现在似乎能够获得q参数的值:

Breakpoint 1, main () at test.cpp:21
21          char** d = NULL;
(gdb) s
22          c(d);
(gdb) s
c (q=0x0) at test.cpp:8
8           cout << q << endl;
(gdb) s
0
9           q = new char*[2];
(gdb) s
13          if (q == NULL)
(gdb) p q
$1 = (char **) 0x2004a0a8
(gdb) p &q
$2 = (char ***) 0x22abd0
(gdb) x 0x22abd0
0x22abd0:       0x2004a0a8

我们改变代码如下:

void c (char** q)
{
    q = new char*[2];
    cout << q << endl;
    if (q == NULL)
        cout<<"NO OK";
    else
        cout<<"OK";
}

生成的函数代码如下所示:(编译-g -ggdb -O0)

.cfi_startproc
pushl   %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl    %esp, %ebp
.cfi_def_cfa_register 5
subl    $40, %esp
movl    $8, (%esp)
call    __Znaj
movl    %eax, -12(%ebp)
movl    -12(%ebp), %eax
movl    %eax, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZNSolsEPKv
movl    $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
movl    %eax, (%esp)
call    __ZNSolsEPFRSoS_E
cmpl    $0, -12(%ebp)
jne L2
movl    $LC0, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
jmp L1

现在,从这段代码看,编译器使用if (q == NULL) $ebp - 12的值。 让我们看一下gdb会话期间的情况:

Breakpoint 1, main () at test.cpp:19
19          char** d = NULL;
(gdb) s
20          c(d);
(gdb) s
c (q=0x0) at test.cpp:8
8           q = new char*[2];
(gdb) s
9           cout << q << endl;
(gdb) s
0x2003a078
11          if (q == NULL)
(gdb) p q
$1 = (char **) 0x0
(gdb) p &q
$2 = (char ***) 0x22abd0
(gdb) p $ebp
$3 = (void *) 0x22abc8
(gdb) p $ebp - 12
$4 = (void *) 0x22abbc
(gdb) x 0x22abbc
0x22abbc:       0x2003a078

看起来gdb在与其实际位置不同的地址查找q。 你可能只是陷入了一个微妙的gcc - gdb交互问题。

通常,调试是在非优化的可执行文件上完成的 (并测量性能 - 在优化的可执行文件上)。 这是因为快速做事并按照他们希望的方式完成它是相互排斥的。

您的c函数可以重写为

void c (char** q)
{
    cout<<"OK";
}

这是因为您在函数参数(即局部变量)上分配了new ed数组。 这意味着代码对世界其他地方没有副作用。 此外, new永远不会返回NULL ,因此q == 0始终为false

编辑:好吧,它实际上比简单的调试/发布差异更复杂。 由于实际问题在于其他地方,为了使这个答案更有用,这就是它应该如何表现(用g++ 4.9.0编译的代码, gdb版本是7.7

未优化的g++ -g

Breakpoint 1, c (q=0x0) at a.cpp:8
8           q = new char*[2];
(gdb) p q
$1 = (char **) 0x0
(gdb) n
9           if (q == NULL)
(gdb) p q
$2 = (char **) 0x611290
(gdb) p q==0
$3 = false
(gdb) n
12              cout<<"OK";
(gdb) p q
$4 = (char **) 0x611290
(gdb) p q==0
$5 = false

优化的g++ -g -O2

Breakpoint 1, c (q=0x0) at a.cpp:8
8           q = new char*[2];
(gdb) p q
$1 = (char **) 0x0
(gdb) n
12              cout<<"OK";
(gdb) p q
$2 = <optimized out>
(gdb)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM