Spooky C++
要約
この記事は、C++における最適化フラグ(-O2)によって引き起こされる、一見不可解な未定義の動作(UB)について解説しています。提示されたコードでは、文字列比較において、最適化されていない場合は`false`となるべき結果が、最適化されている場合にのみ`true`となり、意図しない権限付与が発生します。これは、文字列の長さや一時変数への格納といった特定の条件が満たされた場合にのみ発生する、非常に再現性の低いバグですが、C++の標準やコンパイラの挙動を理解する上で興味深い例として紹介されています。
全文翻訳
Spooky C++
31 Oct 2026
Scary Stories
何か…不気味なものを見たいですか? あなたを夜も眠れなくさせるような、恐ろしく、骨の髄まで凍るような物語を聞きたいですか? さあ、権限を付与するこのプログラムを見てみましょう。
#include <iostream>
#include <string>
#include <string_view>
std::string_view Sanitize(const std::string& input) {
std::string_view sanitized = input;
while (!sanitized.empty() && sanitized.front() == ' ') {
sanitized.remove_prefix(1);
}
return sanitized;
}
int main() {
std::cout << std::boolalpha;
std::string_view username = Sanitize("foobarbazboo");
std::string admin_id = "root_1231231";
std::cout << "Grant foobarbazboo root permissions = " << (username == admin_id) << "\n";
return 0;
}
このコードをコンパイルして実行すると(clang++-19 -std=c++17 -O0 -Wall -Wextra -Wpedantic cursed.cpp -o cursed_clang && ./cursed_clang)、すべて正常に動作し、ユーザーfoobarbazbooはルート権限を取得しません。
Grant foobarbazboo root permissions = false
しかし、ハロウィンの真夜中に、森の中で、ウィジャ盤の上で、鏡の前で「キャンディマン」を5回唱えた後、最適化フラグを-O2に変更してこのコードをコンパイルすると、このプログラムは不思議なことにfoobarbazbooにルート権限を付与します…
clang++-19 -std=c++17 -O2 -Wall -Wextra -Wpedantic cursed.cpp -o cursed_clang_optimized && ./cursed_clang_optimized
Grant foobarbazboo root permissions = true
これは幽霊の仕業でしょうか? 私のコンピューターは h-h-haunted されていますか?
- いいえ - あなたも自分のコンピューターで再現できます。
C++17 は c-c-cursed なのでしょうか?
- はい、しかし超常現象によるものではありません。これはC++20やC++23でも起こり得ます。
clang++-19 -std=c++20 -O2 -Wall -Wextra -Wpedantic cursed.cpp -o cursed_clang_c20 && ./cursed_clang_c23
Grant foobarbazboo root permissions = true
clang++-19 -std=c++23 -O2 -Wall -Wextra -Wpedantic cursed.cpp -o cursed_clang_c23 && ./cursed_clang_c17
私のコンパイラは c-c-cursed なのでしょうか?
- いいえ、なぜならGCCも同様のことを行うからです。
g++ -std=c++17 -O0 -Wall -Wextra -Wpedantic cursed.cpp -o cursed_gcc && ./cursed_gcc
Grant foobarbazboo root permissions = false
g++ -std=c++17 -O2 -Wall -Wextra -Wpedantic cursed.cpp -o cursed_gcc_optimized && ./cursed_gcc_optimized
Grant foobarbazboo root permissions = true
What’s going on
ご想像の通り、これは未定義の動作が直感に反する結果を引き起こす例です。
これは面白い例ですが、この種のバグが実際に(容易に悪用されることも含めて)現れる可能性は低いと思います。なぜなら、この動作は再現が非常に困難だからです。
例えば、これはfoobarbazbooという文字列がadmin_idと同じ長さであり、インラインパラメータとして渡される場合にのみ機能します。入力長を変更したり、foobarbazbooを一時変数に格納するようにプログラムをリファクタリングしたりすると、その動作は消えます。
UBについて何も知らなくても、ほとんどの人はこのコードが不正で奇妙だと考えるでしょう。いくつかの可読性/リファクタリングの原則を守れば、この特定の問題は解消されます。例えば、admin_idをシングルトン/グローバル変数にリファクタリングすると、プログラムは正しく動作します。
とにかく、ハッピーハロウィン
Appendix
uname -r
6.18.54.1-microsoft-standard-WSL2
clang++ -v
Debian clang version 19.1.7 (3+b1)
Target: x86_64-pc-linux-gnu
Debian clang version 19.1.7 (3+b1)
g++ -v
Target: x86_64-linux-gnu
# ...
gcc version 14.2.0 (Debian 14.2.0-19)