【问题标题】:Strange behaviour of gdbgdb的奇怪行为
【发布时间】:2014-07-07 08:36:09
【问题描述】:

我正在调试 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-版本 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,但代码执行方式不同。

【问题讨论】:

    标签: c++ pointers char gdb


    【解决方案1】:

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

    【讨论】:

    • 没有。断点 1, c (q=0x0) at issue.cpp:8 8 q = new char*[2]; (gdb) p q $1 = (char **) 0x0 (gdb) n 9 if (q == NULL) (gdb) p q $2 = (char **) 0x0 (gdb)
    • 做到了。同样的行为。
    • 你明白为什么你会收到这个警告吗?你确定它是假的吗?
    • 是的。我打开了源文件并在构建可执行文件后再次保存它。请您在最后尝试一下。
    • 好的。测试过...我发布了一个新答案,因为我设法重现了您的问题。
    【解决方案2】:

    肯定有什么事情搞砸了 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";
    }
    

    此函数生成的代码如下所示:(compiled -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 交互问题。

    【讨论】:

      【解决方案3】:

      通常在未优化的可执行文件上进行调试(并测量性能 - 在优化的可执行文件上)。这是因为快速做事和完全按照他们想要的方式做事是相互排斥的。

      您的c 函数可以重写为

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

      这是因为你将newed 数组赋值给函数参数,也就是局部变量。这意味着代码对世界其他地方没有副作用。此外,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)
      

      【讨论】:

      • 这个问题似乎与天气无关,或者您没有启用优化。即使使用-O0,它仍在发生。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-06
      • 2023-03-18
      • 1970-01-01
      相关资源
      最近更新 更多