2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「動いてるから大丈夫」が最も危険な言語、それがC++。未定義動作の深淵を覗く

2
Posted at

テストも通った。本番でも動いた。でも「正しい」とは限らない

こんなコードがあります。

int arr[3] = {10, 20, 30};
std::cout << arr[5] << std::endl;  // 配列の範囲外アクセス

手元の環境で実行すると、なぜか 0 が出力されて、クラッシュもしません。
「あれ、範囲外アクセスしてるのにエラーにならないぞ。じゃあ大丈夫か」
大丈夫ではありません。
C++の世界には 「未定義動作(Undefined Behavior = UB)」 という概念があります。
これは「何が起きても文句は言えない。クラッシュするかもしれないし、正常に動くかもしれないし、ハードディスクをフォーマットするかもしれない」という、コンパイラからの最後通告です。
(実際にハードディスクをフォーマットすることはまずありませんが、C++の規格上は「何でも起こりうる」と定義されています)

なぜ「動いている」のに危険なのか

UBの最も恐ろしい点は、「今の環境ではたまたま動いている」だけで、以下のどれかで突然壊れることです。

  • コンパイラのバージョンを上げた
  • 最適化オプションを -O2 に変えた
  • 別のOS/アーキテクチャでビルドした
  • 無関係な場所のコードを変更した

コンパイラの最適化がUBを「消す」例

bool isNegative(int x) {
    return x + 100 < x;  // 符号付き整数のオーバーフロー = UB
}

数学的には、x が非常に大きい場合 x + 100 がオーバーフローして負の数になり、true を返すことがあります。
しかしコンパイラは「符号付き整数のオーバーフローはUBだから、起きないと仮定してよい」と判断し、この関数を最適化で return false; に書き換えます。

コンパイラの思考:
「C++の規格上、符号付きオーバーフローは起きない(UBだから)。
 ということは x + 100 は常に x より大きい。
 つまりこの条件式は常に false。最適化で消そう。」

あなたが書いたロジックが、コンパイラによって予告なく削除される。これがUBの真の恐怖です。

代表的な未定義動作チートシート

❌ 配列の範囲外アクセス
❌ 符号付き整数のオーバーフロー
❌ ヌルポインタのデリファレンス
❌ 初期化されていない変数の使用
❌ delete 済みメモリへのアクセス(use-after-free)
❌ データ競合(マルチスレッドでの同時読み書き)
❌ 厳密なエイリアシング規則の違反

対策:UBを検出する武器

1. コンパイラの警告を最大化する

g++ -Wall -Wextra -Werror -Wpedantic main.cpp

-Werror は警告をエラーとして扱い、無視を許しません。
2. サニタイザーを使う(最強の武器)

g++ -fsanitize=undefined -fsanitize=address main.cpp
./a.out
# 実行時にUBを検知して即座にエラーメッセージを出力してくれる
  • UBSan(-fsanitize=undefined:未定義動作を実行時に検出
  • ASan(-fsanitize=address:メモリ関連のバグを検出
    3. 静的解析ツールの導入
    clang-tidycppcheck などの静的解析ツールでコンパイル前にUBの種を刈り取りましょう。
    C++は「信頼するが検証しない」言語です。コンパイラはあなたのコードにUBがないと善意で仮定し、その仮定に基づいて攻撃的な最適化を行います。「動いてるから正しい」と思った瞬間、あなたはUBの深淵に片足を踏み入れています。
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?