【C言語】
printf(書式%s)にNULLポインタが渡る時 “(null)”の表示を期待しないこと

warning: ‘%s’ directive argument is null

[-Wformat-overflow=]


■この記事の概要

この記事では、C言語のprintfで書式指定子%sNULLポインタを渡すと未定義動作となる問題を解説しています。(null)と表示されるケースもありますが、セグメンテーションフォルトが発生することもあるため、NULLを渡さないようにする対策が推奨されています。例えば、戻り値チェックを徹底することで安全性を確保できます。


■書式%sにNULLポインタが渡るとSegmentation fault

#include    <stdio.h>
int main(void){
    printf("1:%d\n",    0);
    printf("2:%c\n",    '\0');
    printf("3:%s\n",    "");
    printf("4:%s\n",    NULL);//★ 未定義動作
    printf("%s\n",      NULL);//★ 未定義動作    
    fflush(stdout);
}

Windows系のコンパイラでは書式%sにNULLポインタが渡ると
“(null)”と表示されるそうですが、
Linux系(gcc,clang)では
コンパイラと最適化レベルで結果が異なります。
”(null)”と表示されたり
Segmentation faultと表示して異常終了したりします。

●筆者環境下の実行結果

./a.out
1:0
2:
3:
4:(null)
Segmentation fault (コアダンプ)

■戻り値をチェックしないでNULLポインタとなる例

#include    <string.h>
#include    <stdio.h>
int main(void){
    const char *cp = "abc,def,ghi";    
    printf("%s\n",cp);

    cp = strchr(cp,',');
    printf("%s\n",cp);
    fflush(stdout);

    cp = strchr(cp+1,',');
    printf("%s\n",cp);
    fflush(stdout);

    cp = strchr(cp+1,',');
    printf("%s\n",cp);
    fflush(stdout);
}


書式%sにNULLポインタを渡すのはC言語規格外の未定義動作なので
職業プログラマはきちんとstrchr()の返却値をチェックして
書式%sにNULLポインタが渡らないようにチェックしましょう。

●筆者環境下の実行結果

./a.out
abc,def,ghi
,def,ghi
,ghi
Segmentation fault (コアダンプ)

参考:

FIO47-C. 書式指定文字列を正しく使う

https://www.jpcert.or.jp/sc-rules/c-fio47-c.html