まあ、当たり前のことですが…
#include <stdio.h>
#include <stdlib.h>
__attribute__((noinline)) int func(int n){
for(volatile int i=0;i<n;i++)puts("hello world");
fflush(stdout);
getenv("PATH");
}
int main(){
func(3);
}
これをgccに食わせると、no return statement in function returning non-void
警告が発生します。
この警告に関して、返値を呼び出し側で使わなければ動作に影響はないと思っている人は多いと思います(私もその一人でした)。
しかし実際には、以下のようになります12。
処理系 | func呼び出し結果 |
---|---|
gcc | 返値不定 |
g++-6以下 | 0が返る |
g++-7 | 返値不定 |
g++-8以上 | segmentation fault |
clang | 返値不定 |
clang++ | segmentation fault |
icc | 返値不定 |
icpc | 返値不定 |
icx | 返値不定 |
icpx | 返値不定 |
msvc | (値を返さないのはそもそも警告ではなくコンパイルエラー) |
g++-8以上およびclang++3では スタックポインタを復元するアセンブリもretアセンブリも出力されませんでした。 segvまっしぐらです4。
今まで気づかなかったのが不思議です。。
-
https://gcc.godbolt.org/ で確認しました。すごく便利なサイトですね。 ↩
-
最適化ありの場合です。 ↩
-
CとしてコンパイルしたときとC++としてコンパイルしたときの挙動が違う…。 ↩
-
しかもこれ系はgdbで正しいスタックトレースが取得できなくなるので極めてたちが悪い。 ↩