[C++] 196 GDBによるデバッグ例 stoi関数

[Windows11, MinGW g++ 9.2.0, FLTK 1.3.8, NO IDE]

MacOSから移植中のカラーアプリについてWindows環境のみでアプリが落ちる現象が発覚しましたので、早速GDBデバッガで調査しました。

コンパイル時に-Ogオプションを追加しないとオブジェクトファイルのデバッグへの最適化ができないので要注意です。実際に-Ogオプションなしでコンパイルすると関数指定や行数指定のブレークポイント設定が正確にできませんでした。

DEBUG = -Og -g

“b btnAction.cpp:showColor”コマンドでbtnAction.cppのshowColor関数にブレークポイントを設定し、rコマンドでアプリを実行しました。nコマンドでは関数はスキップして次の行に進み、sコマンドでは関数にも入り込んで次の行に進みます。

調査の結果、自製ライブラリColorConvertのZeroToRGB関数にあるstoi関数辺りに原因があることが判明しました。

対策:
invalid argumentエラーを例外処理するようにした。

clang++ではデフォルトで例外処理を包含しているようです。stoi関数の引数がNULLでもエラーになりません。clang++が甘々なのか、MinGWが厳しいのか。

int red;
int green;
int blue;

try{
    red = stoi(red0);
    green = stoi(green0);
    blue = stoi(blue0);
}catch(const std::invalid_argument& e){
    cout << "invalid argument" << endl;
}
>gdb ColorSample.exe
Reading symbols from ColorSample.exe...done.
(gdb) b btnAction.cpp:showColor
Breakpoint 1 at 0x406510: btnAction.cpp:showColor. (2 locations)
(gdb) r
Starting program: ColorSample.exe
[New Thread 6864.0x4334]
[New Thread 6864.0x968]
[New Thread 6864.0x2350]
[New Thread 6864.0x44b4]
locale Japanese_Japan.932
Japan detect
[New Thread 6864.0x43c0]
[New Thread 6864.0x3258]
[New Thread 6864.0x3bd8]

Breakpoint 1, showColor () at C:/FLTK/fltk-1.3.8/include/FL/Fl_Button.H:102
102       char value() const {return value_;}
(gdb) s
516         input_code = code_input->value();
(gdb) s
value (this=0xf485e0) at C:/FLTK/fltk-1.3.8/include/FL/Fl_Input_.H:244
244       const char* value() const {return value_;}
(gdb) n
showColor () at .\src\btnAction.cpp:516
516         input_code = code_input->value();
(gdb) n
517         if (input_code == ""){
(gdb) n
533         if (onoff_zero == 1){
(gdb) s
534             ToZeroConvert();
(gdb) s
ToZeroConvert () at .\src\btnAction.cpp:196
196         const char* input_code0 = code_input->value();
(gdb) p input_code0
$1 = <optimized out>
(gdb) s
value (this=0xf485e0) at C:/FLTK/fltk-1.3.8/include/FL/Fl_Input_.H:244
244       const char* value() const {return value_;}
(gdb) s
ToZeroConvert () at .\src\btnAction.cpp:197
197         input_code = string(input_code0);
(gdb) p input_code
No symbol "input_code" in current context.
(gdb) s
basic_string<> (__a=..., __s=0xf5f498 "0x483D", this=0xdaf334) at .\src\btnAction.cpp:197
197         input_code = string(input_code0);
(gdb) p input_code
No symbol "input_code" in current context.
(gdb) s
_Alloc_hider (__a=..., __dat=0xdaf33c "\375\023爽リ\023爽蝗^ツ\032        \r", this=0xdaf334)
    at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/ext/new_allocator.h:83
83            new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }
(gdb) s
basic_string<> (__a=..., __s=0xf5f498 "0x483D", this=0xdaf334)
    at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:527
527           { _M_construct(__s, __s ? __s + traits_type::length(__s) : __s+npos); }
(gdb) n
ToZeroConvert () at .\src\btnAction.cpp:197
197         input_code = string(input_code0);
(gdb) n
199         if (input_code.find("#") != string::npos){
(gdb) n
230         } else if (input_code.find("0x") != string::npos){
(gdb) n
[New Thread 6864.0x3a8c]
232             code_zero = input_code;
(gdb) s
operator= (__str=..., this=0x52f094 <code_zero[abi:cxx11]>) at .\src\btnAction.cpp:232
232             code_zero = input_code;
(gdb) s
assign (__str=..., this=0x52f094 <code_zero[abi:cxx11]>)
    at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:1364
1364          assign(const basic_string& __str)
(gdb) s
_fu21___ZSt4cout () at .\src\btnAction.cpp:235
235             baseColor = CC.ZeroToRGB(input_code);
(gdb) s
basic_string (__str=..., this=0xdaf3c4) at .\src\btnAction.cpp:235
235             baseColor = CC.ZeroToRGB(input_code);
(gdb) s
_Alloc_hider (__a=<optimized out>, __dat=0xdaf3cc "\a", this=0xdaf3c4)
    at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/ext/new_allocator.h:83
83            new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }
(gdb) s
basic_string (__str=..., this=0xdaf3c4) at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:451
451           { _M_construct(__str._M_data(), __str._M_data() + __str.length()); }
(gdb) s
_M_data (this=<optimized out>) at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:186
186           _M_data() const
(gdb) s
basic_string (__str=..., this=0xdaf3c4) at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:936
936           length() const _GLIBCXX_NOEXCEPT
(gdb) s
451           { _M_construct(__str._M_data(), __str._M_data() + __str.length()); }
(gdb) s
_M_construct<char*> (__end=0x53b0fa <input_code[abi:cxx11]+14> "", __beg=0x53b0f4 <input_code[abi:cxx11]+8> "0x483D",
    this=0xdaf3c4) at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:451
451           { _M_construct(__str._M_data(), __str._M_data() + __str.length()); }
(gdb) s
_M_construct_aux<char*> (__end=0x53b0fa <input_code[abi:cxx11]+14> "",
    __beg=0x53b0f4 <input_code[abi:cxx11]+8> "0x483D", this=0xdaf3c4)
    at c:/mingw/lib/gcc/mingw32/9.2.0/include/c++/bits/basic_string.h:263
263             _M_construct(_InIterator __beg, _InIterator __end)
(gdb) n // ここでアプリが落ちた
[New Thread 6864.0x2a54]
[New Thread 6864.0x24c4]
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoi
[Inferior 1 (process 6864) exited with code 03]
(gdb) quit
GCC公式ドキュメント -Ogオプションに関する記述