Yoh2の日記: 無限再帰を一瞬で 5
日記 by
Yoh2
clang-3.0にて。
// hoge.c
#include <stdio.h>
void func(void)
{
func();
}
int main(void)
{
func();
puts("The code clang generates is so fast.");
return 0;
}
ビルド & 実行。
$ clang -O2 hoge.c
$ ./a.out
The code clang generates is so fast.
わー。すごくはやーい。むげんさいきよびだしをいっしゅんでぬけたぞー……?
規格上どうなるべきか (スコア:1)
普通はスタックオーバーフローで Segmentation fault になるよね…と思ったところで、関数の無限再帰呼出によるスタックオーバーフロー時の動作って規格的にはどうなっているのかが気になりました。
未定義とかなら、結果として puts(...); による出力が行われるのもアリかもしれないと思ったので。
で、規格書はまだ見てないんですが、『スタックオーバーフローの仕様 - まめめも [hatena.ne.jp]』・『スタックオーバーフローの仕様の続き - まめめも [hatena.ne.jp]』あたりによると、Cの規格の範囲では無限に関数を呼び出し続けなければならないと考えていいのかな?
それと、アセンブリ出力も見てみたいなぁ、とリクエスト。
The Only Nerd Thing To Do
-たったひとつのアレゲなやりかた-
Re:規格上どうなるべきか (スコア:1)
ほい。clang-3.0で -O2 を付けた場合。アーキテクチャはamd64ね。
要するに、関数に入って即座にret。
実際の所は、main()の中で、func()がインライン展開されちゃってfunc()が呼ばれることはありませんが。
再帰呼び出しの最適化がどうかかるか調べていたらおかしなアセンブリコードが見えたのでおや? と思ったのが発端。
おまけ: gcc-4.5.3で -O2 を付けた場合:
単なる無限ループに。clangでもこうなることを期待してたんだけどなぁ。
巧妙に潜伏したバグは心霊現象と区別が付かない。
Re:規格上どうなるべきか (スコア:1)
そういえば、gccの出力、ret命令がないな。戻らないということをきっちり判ってるのかな?
巧妙に潜伏したバグは心霊現象と区別が付かない。
Re: (スコア:0)
インライン展開でretだけになるって、lim(x→0)な気分だ...
gcc 4.2.1 (x86) でも (スコア:1)
FreeBSD 上の gcc 4.2.1 20070719 (x86) でも、 -O1・-O2 で clang 3.0 と同じようなことが起きました。
こちらのアセンブリ出力は以下の通りで、即座に ret ではなく余計な pushl・movl・popl が入っていました。
ちなみに試したのはさくらのレンタルサーバ上で。
The Only Nerd Thing To Do
-たったひとつのアレゲなやりかた-