Security Enhancements in the CRT

Visual C++ 2005 だとセキュリティを高めた標準 C ライブラリ関数というものが用意されてるらしい。


http://whidbey.msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vccrt/html/d9568b08-9514-49cd-b3dc-2454ded195a3.asp


strcpy() なんかは、destination のサイズを指定する strcpy_s() というのが用意されてるし、fopen() の代替の fopen_s() というのも用意されている。


またエラーを返す型として error_t が用意されていて、error_t 型で返される値は 0 が成功、それ以外はエラーという分かりやすい仕様となっている。
ぱっと見た感じ、error_t はエラー値だけで、その他の値は別の方法で返すようになっているっぽい。つまり例えば、とある ID を作成する関数の場合、返り値でエラー値とIDを同時に返すことが多い。

int res = create_id();
if (res < 0) {
    // error
} else {
    // success
    int id = res;
    ...
}

これが、error_t を使う場合、error_t はエラー値しか返さないため、ID は引数ポインタで返す必要がある。

int id;
error_t err = create_id(&id);
if (err < 0) {
    // error
} else {
    // success
    ...
}

パフォーマンスの面で言えば前者の方に利があるが、コードと変数の分かりやすさという点では後者の方が優れていると思う。
なので error_t という型を用意したこと、そしてそれをエラー専用の型という意味にしているというのは良い事だと思う。できればこの考え方が広まって欲しい。


次に fopen() と fopen_s() の型は以下のようになっている。

FILE *fopen(
   const char *filename,
   const char *mode
);
errno_t fopen_s( 
   FILE** pFile,
   const char *filename,
   const char *mode 
);

fopen() はエラー時に NULL を返し、何のエラーだったかを errno を参照しなくてはいけなかったのに対し fopen_s は errno_t でエラー値を返すため errno を参照する必要はなくなっている(ただし fopen_s() も errno に値はセットするみたい)
Windows/Mac/Linux などの PC プログラミングしている人にとってみれば、返り値でエラーが返ろうが errno を参照しようが大差ないように見えるが、組み込み系OSでスレッドローカルストレージが無い環境だと、スレッドが切り替わるたびに errno が別スレッドで上書きされる可能性があるため errno は使い物にならない。
よって fopen_s() のようにエラー値は返り値で返すようにするというスタイルは組み込み系にとってありがたい仕様になるはず。


ただその考えでいけば、すべての関数は返り値でエラーを返し、errno は使う必要がないという方向にすべきだが、sprintf_s() はそうなっていない。errno にエラー値をセットするようになっている。

int sprintf_s(
   char *buffer,
   size_t sizeOfBuffer,
   const char *format [,
      argument] ... 
);

これは次のように定義されるべきだと思う。

error_t sprintf_s(
   char *buffer,
   size_t sizeOfBuffer,
   size_t *outCount,
   const char *format [,
      argument] ... 
);

あとは strncpy() と違い strcpy_s() は必ず NULL ターミネートされるようになってるし、今まで使い物にならなかった gets() には gets_s() が用意された。他にも C 標準関数の悪名高いもの (strtokとか) に関してもそれぞれ代替関数が用意されているようだ。


上記の error に関する箇所は再度検討したほうがよさそうに思えるが、その他はまぁいいのではと思う。
今後は、VC++ だけではなくちゃんと標準委員会で議論したうえで標準に組み込んでもらうという方向に持っていって欲しいなぁ。fopen_s() とか使いたいし。