5.1. C や C++ の危険なところ

C ユーザは、確保されている領域を越えることはありえないと確証できなければ、 境界をチェックしない危険な関数を使うべきではありません。 通常使用を避けた方が良い(確実に防御すべき)関数には、strcpy(3)や strcat(3)、 sprintf(3)(親戚に当たる vsprintf(3))、gets(3) があります。 その代わりとして、strncpy(3)や、strncat(3)、snprintf(3)や fgets(3)の使用を お薦めします。詳しくは下記で論じますので読んでください。 strlen(3)は NIL が必ず存在するのが確実でなければ、使用を避けてください。 scanf()系 (scanf(3)や fscanf(3)、sscanf(3)、vscanf(3)、vsscanf(3)、vfscanf(3)) は、使用するのに危険な場合が多々あります。最長値を把握せずにデータを文字列に 渡さないでください(とりわけ %s という形式は問題になります)。 バッファオーバーランしてしまうかもしれない他の危険な関数として(その使い方 にもよりますが)、realpath(3)や getopt(3)、getpass(3)、streadd(3)、strecpy(3)、 strtrns(3)があります。 getwd(3)には注意しないといけません。getwd(3)に送るバッファは、たった PATH_MAX バイトしかありません。

snprintf()系は残念ながらもっと問題を抱えています。 sprintf() と違って snprintf()は、公式には ISO 1990(ANSI 1989)規格の標準 C 関数ではありません。 したがって、システムすべてに snprintf() があるわけではありません。 さらに困ったことに、あるシステムの snprintf()は、バッファオーバーフロー を実質防ぎません。ただ sprintf を呼び出すだけです。 Linux の libc4 という古いバージョンは、「libbsd」ライブラリに依存して いました。これが実に嫌らしいライブラリでした。古い HP のシステムにも 同様なものがありました。 Linux の最近の snprintf は正しく動作することがわかっていて、要求された 境界値をたしかに守っています。 snprintf() の返り値もさまざまです。 Single Unix Specification (SUS) version 2 と C99 規格では、何が返るか違って います。 結果的にわかったのは、snprintf のバージョンには文字列が NIL で終端するのを 保証しないものがある、という事実です。文字列が長すぎれば、NIL がまったく ないでしょう。 glib ライブラリ(GTK のベースになっているもので、GNU C ライブラリの glib とは 違います)には g_snprintf() があります。返り値が一貫しており、常に NIL で終端 します。もっと重要なのは、バッファの長さを常に守っている点です。 【訳註:C99 規格は、「ISO/IEC 9899:1999 - Programming Language C」を指し ます。詳しくは http://seclan.dll.jp/c99d/ を参照してください】