x86-64 コードの微妙なクラッシュを把握するのに半日を費やしただけなので、これは他の人への警告です。これが他の場所で扱われているのを見たことがありません。
適切な宣言なしで libc 関数を使用すると、gccは int を返すと想定します。たとえば、setlocale()はint setlocale()であると想定され、EAX で 32 ビットの int 値が返されます。
この戻り値を暗黙的または明示的なキャストによってポインターに変換しようとすると、呼び出された関数が RAX で有効な 64 ビン ポインター値を返したとしても、符号拡張によって 32 ビットから 64 ビットへの変換が強制されます。例えば
char *p = setlocale(0, 0); // bear with me for a second
にコンパイルされます
1c: b8 00 00 00 00 mov $0x0,%eax
21: e8 00 00 00 00 callq 26 <hard_locale+0x26>
26: 48 98 cltq ; <--- eax is expanded in rax
GCC は次のように伝えようとします。
warning: initialization makes pointer from integer without a cast
明示的なキャストを追加すると、警告が次のように変わり、問題が示されます。
warning: cast to pointer from integer of different size
運が良ければ何も起こりませんが、メモリ内のポインタに対して大きな値が返された場合は、次のようにめちゃくちゃになります。
function returns in RAX: 0x07ffff7b9705e
cltq considers EAX with negative sign: 0xf7b9705e
now RAX is: 0xfffffffff7b9705e
あなたのポインターは無効です。
修正と解決策:
常に適切な関数宣言を使用する
-Wall -Werrorは、x86-64 コンパイラではデフォルトでオンにする必要があります。