とある Linux コンテナで動くプロセスを GDB でデバッグしている最中に glibc の関数を追っていて、以下のようなコードを見つけました
(gdb) l
156 void
157 __libc_fatal (const char *message)
158 {
159 /* The loop is added only to keep gcc happy. */
160 while (1)
161 __libc_message ("%s", message);
162 }
はて ... ?
The loop is added only to keep gcc happy.とは?- この while(1) はなんのためにあるのだ?
わからんので エイっと AI に聞いてみました。
以下は Microsoft 365 Copilot Chat の回答です。他の AI 回答も予々一緒で、妥当っぽい回答な気がする。
この while (1) ループは、意図的に無限ループにしてプログラムを停止させるために使われています。 関数 __libc_fatal は、glibc(GNU Cライブラリ)の内部で致命的なエラーが発生したときに呼ばれる関数です。以下のような目的があります:
目的と意味
致命的エラーの通知
__libc_message("%s", message);によって、エラーメッセージを表示します。プログラムの停止 while (1) によって、関数から戻らず、プログラムを永久に停止させます。これは、致命的なエラーが発生した後に、処理を続けることが危険であるためです。
最適化回避
コメントにある「The loop is added only to keep gcc happy.」は、GCC(GNU Compiler Collection)が最適化の際にこの関数を「戻る可能性がある」と誤認しないようにするためです。無限ループにすることで、コンパイラに「この関数は絶対に戻らない」と明示できます。
補足
通常、こうした関数は
__attribute__((noreturn))を使って「戻らない関数」として宣言されますが、念のために while (1) を入れておくことで、コンパイラの警告や最適化の問題を防いでいます。
glibc のソースへのリンク
upsteream である glibc 2.34 へのリンクを貼っておきます 1
ソース
void __libc_fatal (const char *message) { /* The loop is added only to keep gcc happy. */ while (1) __libc_message (do_abort, "%s", message); } libc_hidden_def (__libc_fatal)
abort() の文字列を見て過去に書いた記事を思い出す
__libc_message() は内部で abort() を呼び出すようです。
/* Abort with an error message. */ void __libc_message (enum __libc_message_action action, const char *fmt, ...) { ... 略 if ((action & do_abort)) /* Kill the application. */ abort (); }
そういえば、ずいぶん前に abort() の実装を追って調べて、テックブログにまとめたのを思い出しました。
abort() にも while(1) で HLT 命令を呼び出すコードがありますね ! 詳細はブログ読んでね (宣伝)
while (1) /* Try for ever and ever. */ ABORT_INSTRUCTION;