【VSC】ERROR:GDB exited unexpectedly.


【VSC】ERROR:GDB exited unexpectedly.

记录一次调试所遇bug的查找历程

问题描述

ERROR: GDB exited unexpectedly. Debugging will now abort.
The program has exited with code -1 (0xffffffff).

vscode成功进入gdb调试,运行过程中意外退出。

bug案发现场


图1 案发现场

源代码

main.cpp

#include 
#include "13.h"
int main()
{
    Solution soLuTion;
    std::cout << soLuTion.romanToInt("MCMXCIV") << std::endl;
    std::cout << sizeof("MCMXCIV") << std::endl;
    return 0;
}

13.cpp

#include 
#include 
#include "13.h"
int Solution::romanToInt(std::string s)
{
    // std::cout << s[0] << std::endl;
    int tempNum = 0;
    char tempChar = '0';
    for (int getC = 0; getC < s.size(); getC++)
    {
        switch (s[getC])
        {
        case 'I':
            tempNum += 1;
            break;
        case 'V':
            if (tempChar == 'I')
            {
                tempNum += 4 - 1;
            }
            else
            {
                tempNum += 5;
            }
            break;
        case 'X':
            if (tempChar == 'I')
            {
                tempNum += 9 - 1;
            }
            else
            {
                tempNum += 10;
            }
            break;
        case 'L':
            if (tempChar == 'X')
            {
                tempNum += 40 - 10;
            }
            else
            {
                tempNum += 50;
            }
            break;
        case 'C':
            if (tempChar == 'X')
            {
                tempNum += 90 - 10;
            }
            else
            {
                tempNum += 100;
            }
            break;
        case 'D':
            if (tempChar == 'C')
            {
                tempNum += 400 -100;
            }
            else
            {
                tempNum += 500;
            }
            break;
        case 'M':
            if (tempChar == 'C')
            {
                tempNum += 900 - 100;
            }
            else
            {
                tempNum += 1000;
            }
            break;
        default:
            break;
        }
        tempChar = s[getC];
    }
    return tempNum;
}

13.h

#pragma once
#include 
class Solution 
{
public:
    int romanToInt(std::string s);
};

更多日志

=thread-group-added,id="i1"
GNU gdb (GDB) 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Warning: Debuggee TargetArchitecture not detected, assuming x86_64.
=cmd-param-changed,param="pagination",value="off"
[New Thread 15724.0x744]
[New Thread 15724.0x258c]
[New Thread 15724.0x2ba0]
[New Thread 15724.0x2950]

Thread 1 hit Breakpoint 1, main () at D:\myproject\CPP\learn\leecode\main.cpp:6
6	    std:: cout << soLuTion.romanToInt("MCMXCIV") << std::endl;
Loaded 'C:\Windows\SYSTEM32\ntdll.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\kernel32.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\KernelBase.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\msvcrt.dll'. Symbols loaded.
Loaded 'D:\solfware\mingw64\mingw64\opt\bin\libgcc_s_seh-1.dll'. Symbols loaded.
Loaded 'D:\solfware\mingw64\mingw64\opt\bin\libwinpthread-1.dll'. Symbols loaded.
Loaded 'D:\solfware\mingw64\mingw64\bin\libstdc++-6.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\user32.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\win32u.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\gdi32.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\gdi32full.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\msvcp_win.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\ucrtbase.dll'. Symbols loaded.
Loaded 'C:\Windows\System32\imm32.dll'. Symbols loaded.
Execute debugger commands using "-exec ", for example "-exec info registers" will list registers in use (when GDB is the debugger)
ERROR: GDB exited unexpectedly. Debugging will now abort.
The program 'D:\myproject\CPP\learn\leecode\build\13' has exited with code -1 (0xffffffff).

launch.json文件配置

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [

        {
            "name": "g++.exe - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}\\build\\13",
            "args":  [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "D:\\solfware\\mingw64\\mingw64\\bin\\gdb.exe",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

使用平台

OS: WIN 10 64bit
g++ --version: g++.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
gdb --version: GNU gdb (GDB) 8.1
vscode version: 1.67.0

问题排查

看看是不是gdb的问题

使用gdb命令行调试

gdb .\13.exe

调试过程

(gdb) b 6
Breakpoint 2 at 0x401563: file D:\myproject\CPP\learn\leecode\main.cpp, line 6.
(gdb) r
Starting program: D:\myproject\CPP\learn\leecode\build\13.exe 
[New Thread 5436.0x241c]
[New Thread 5436.0x3e9c]
[New Thread 5436.0x2b38]
[New Thread 5436.0x2ec0]

Thread 1 hit Breakpoint 2, main () at D:\myproject\CPP\learn\leecode\main.cpp:6
6           std:: cout << soLuTion.romanToInt("MCMXCIV") << std::endl;
(gdb) s
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:7
7           int tempNum = 0;
(gdb) watch tempNum
Hardware watchpoint 3: tempNum
(gdb) n
8           char tempChar = '0';
(gdb) n
9           for (int getC = 0; getC < s.size(); getC++)
(gdb) n
11              switch (s[getC])
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 0
New value = 1000
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:75
75                  break;
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 1000
New value = 1100
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:55
55                  break;
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 1100
New value = 1900
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:75
75                  break;
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 1900
New value = 1910
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:35
35                  break;
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 1910
New value = 1990
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:55
55                  break;
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 1990
New value = 1991
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:15
15                  break;
(gdb) c
Continuing.

Thread 1 hit Hardware watchpoint 3: tempNum

Old value = 1991
New value = 1994
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:25
25                  break;
(gdb) c
Continuing.

Watchpoint 3 deleted because the program has left the block in
which its expression is valid.
0x0000000000401599 in main () at D:\myproject\CPP\learn\leecode\main.cpp:6
6           std:: cout << soLuTion.romanToInt("MCMXCIV") << std::endl;
(gdb) c
Continuing.
1994
[Thread 5436.0x2ec0 exited with code 0]
[Thread 5436.0x2b38 exited with code 0]
[Thread 5436.0x3e9c exited with code 0]
[Inferior 1 (process 5436) exited normally]

可以看出gdb是可以正常调试的,那么应该不是gdb的问题(误)

看看是不是平台的问题

同样的程序我跑到ubuntu虚拟机上用VSCdebug,是可以正常调试的。

内核版本

LINUX: 5.4.0-109-generic
Ubuntu:18.04.1
GCC: 7.5.0
GDB: 8.1.1

成功快照


图2 linux虚拟机平台

 

ok,真相了,是平台的差异导致的。那到底是哪里的差异呢?

灵机一动:如果我不watch变量看看

我不watch特定变量,在WIN10下试试debug

图3 不用watch

是可行的!那么找到突破口了,经过我的测试,我找到了引起意外退出的罪魁祸首,s[getC]。

Howerver

在我的虚拟机里,在创建getC这个变量的时候,会先给getC赋个值,具体可以观察图2,这个是是随机的一长串数字,有时是正,有时是负,大概有-996661983,有297860271等,一开始我想到了越界的问题,但是对于虚拟机来讲,它是可以正常调试的,getC的值在创建前的那一刹那会附一个上述的那些值,但这应该不是重点,因为创建完它就被赋予了0,然后我watch s[getC]也不应该有影响。

会不会是gdb版本的问题

回到我的WIN10环境,我不禁陷入了沉思,我又看了看两种环境下gdb的版本,决定再验证一下是不是gdb的问题。

再一次使用gdb命令行调试,我特意watch 了 s[getC],你猜怎么着,也闪退了。

调试过程

(gdb) l
1       #include 
2       #include "13.h"
3       int main()
4       {
5           Solution soLuTion;
6           std::cout << soLuTion.romanToInt("MCMXCIV") << std::endl;
7           std::cout << sizeof("MCMXCIV") << std::endl;
8           return 0;
9       }(gdb) b 6
Breakpoint 1 at 0x401563: file D:\myproject\CPP\learn\leecode\main.cpp, line 6.
(gdb) r
Starting program: D:\myproject\CPP\learn\leecode\build\13.exe 
[New Thread 17844.0x18a4]
[New Thread 17844.0x33c]
[New Thread 17844.0x2960]
[New Thread 17844.0x4300]

Thread 1 hit Breakpoint 1, main () at D:\myproject\CPP\learn\leecode\main.cpp:6
6           std::cout << soLuTion.romanToInt("MCMXCIV") << std::endl;
(gdb) s
Solution::romanToInt (this=0x62fddf, s="MCMXCIV") at D:\myproject\CPP\learn\leecode\13.cpp:7        
7           int tempNum = 0;
(gdb) watch s[getC]
No symbol "getC" in current context.
(gdb) n
8           char tempChar = '0';
(gdb) n
9           for (int getC = 0; getC < s.size(); getC++)
(gdb) watch s[getC]
PS D:\myproject\CPP\learn\leecode\build>

嗯,我大概找到原因了,ERROR: GDB exited unexpectedly.这个错误是由
gdb 8.1 在调试我程序里的变量 s[getC] 时造成的。

结论

gdb 8.1极有可能存在某个bug会造成我所遇到的 gdb exited unexpected。

在网上冲了会浪,发现有人也遇到了和我同样的问题。某不知名人士所遇得bug。他的问题几乎和我相同,同样的string,同样的去watch string里的一个字符,同样的for循环,哈哈,这是变相遇到知音了。

github里也有个issue差不多佐证了我的想法。