C++
 Computer >> コンピューター >  >> プログラミング >> C++

GDBを使ってC/C++のセグメンテーションエラーを特定する方法

セグメンテーションエラーとは

セグメンテーションエラー(Segmentation Fault)は、実行時に発生するエラーの一つで、メモリへの不正なアクセスが原因で起こります。代表的な発生要因としては、以下のようなケースが挙げられます。

  • 無効な配列インデックスへのアクセス
  • NULLポインタや未初期化ポインタの参照
  • アクセスが制限されているアドレス領域への読み書き

本記事では、デバッガツール「GDB」を使用して、この種のエラーを効率的に検出・特定する手順を解説します。

サンプルコード

まずは、意図的にセグメンテーションエラーを発生させるサンプルコードを見てみましょう。

#include <stdio.h>
main() {
    int* ptr = NULL;
    *ptr = 1; // 存在しないメモリ位置へアクセスしようとしている
    printf("%p\n", ptr);
}

このコードでは、NULLポインタに対して値を代入しようとしているため、実行時に必ずセグメンテーションエラーが発生します。

コンパイルと実行

次のコマンドでコードをコンパイルし、実行します。「-g」オプションを付けることでデバッグ情報がバイナリに埋め込まれ、後ほどGDBでの解析が格段に容易になります。

gcc –g program_name.c
./a.out

実行結果

soumyadeep@soumyadeep-VirtualBox:~/Cpp_progs$ ./a.out
Segmentation fault (core dumped)

予想どおり、セグメンテーションエラーが発生しました。しかし、この出力だけではエラーの原因となった箇所は分かりません。そこでGDBの出番です。

GDBでエラー箇所を特定する手順

ステップ1: GDBの起動

次のコマンドでGDBを起動します。

gdb ./a.out core
soumyadeep@soumyadeep-VirtualBox:~/Cpp_progs$ gdb ./a.out core
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
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-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<https://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
/home/soumyadeep/Cpp_progs/core: No such file or directory.
(gdb)

※ コアファイルが存在しないという警告が表示されても問題ありません。GDB上からプログラムを直接実行すれば解析可能です。

ステップ2: プログラムの実行

GDBのプロンプトで「r」(run)と入力してEnterキーを押すと、プログラムが実行され、エラー発生箇所で停止します。

Starting program: /home/soumyadeep/Cpp_progs/a.out

Program received signal SIGSEGV, Segmentation fault.
0x000055555555465e in main () at 1230.find_seg_error.c:5
5 *ptr = 1; //trying to access unknown memory location
(gdb)

出力を確認すると、「SIGSEGV」シグナルを受信したこと、そしてエラーが発生したのがソースファイルの5行目、つまり *ptr = 1; の行であることが明確に示されています。これでエラー箇所を特定できました。

ステップ3: GDBの終了

エラーを確認したら、「quit」コマンドでGDBを終了します。

(gdb) quit
A debugging session is active.

Inferior 1 [process 2794] will be killed.

Quit anyway? (y or n) y

デバッグ中のプロセスが強制終了される旨の確認を求められるので、「y」と入力して終了します。

まとめ

GDBを活用すれば、セグメンテーションエラーが発生した正確な行番号と原因となる命令を簡単に特定できます。大規模なプロジェクトでも同じ手順でデバッグできるため、C/C++開発者にとってGDBの基本的な使い方を習得しておくことは非常に有益です。コンパイル時には必ず「-g」オプションを付けておくことを忘れないようにしましょう。

  1. C++とOpenCVを使って線を描画する方法

    OpenCVで線を描画するには、始点と終点の2つの座標が必要です。さらに、線を描くためのキャンバス(描画領域)も用意しなければなりません。線を描画するために必要な要素OpenCVでは、キャンバスとして機能するのが行列(Mat)です。この行列に対して、線の始点と終点を定義し、加えて以下の情報も指定します。線の色線の太さつまり、OpenCVで線を描くには、行列・2つの点・色・線の太さという4つの要素を宣言しておく必要があります。必要なヘッダーファイルOpenCVで線を描画するには、<imgproc.hpp>ヘッダーをインクルードします。これは、line()関数がこのヘッダー内で定義され

  2. C++プログラムから外部アプリケーション(メモ帳など)を起動する方法

    この記事では、C++プログラムを使ってメモ帳(Notepad)などのサードパーティ製アプリケーションを起動する方法を解説します。実装は非常にシンプルで、コマンドプロンプトで使うコマンドをそのままC++から呼び出すだけで実現できます。ポイントとなるのは、標準ライブラリの system() 関数です。この関数の引数にアプリケーション名(コマンド)を文字列として渡すと、OSがそのコマンドを実行し、対応するアプリケーションが起動します。サンプルコード#include <iostream> using namespace std; int main() { cout <<