« XSI 6 Mod Tool - XNA 連携チュートリアル | トップページ | XSI 6 Mod Tool - XNA 連携チュートリアル(2) »

2007.09.20

VC++ 2005 セキュリティーコード

普段プログラムはMicrosoftのVisual C++ 2003で組んでいるけど、ノートパソコンにはMicrosoft Visual C++ 2005 Express Edition + Microsoft Platform SDKをインストールして使っている。
※VC++ 2005 Express Edition と PlatformSDK は 「タダ・無料・フリー」 昔じゃ考えられないな。あぁけどLSI-C86試食版とか使ったっけ。

ところが新しいだけあって(2008の宣伝をどっかでちらっとみたけど)2002や2003で組んだコードだと警告(warning)やエラー(error)がどっちゃりと出てくる。
系統的には2種類で文字コードの問題とセキュリティーコードの問題らしい。

今回はそのセキュリティーコードの話をしようと思う。

Gw20070919210830
HTMLタグ書くのめんどくさいので画像でよろしく

こんなソースコードがあったとしよう。
めんどくさかったのでウィーザードから生成したため、_tmain とか stdafx.hとかインクルードしているが、_tmain は通常のmain関数、stdafx.hはstdlib.hとかstring.hとかをインクルードしているという感じに置き換えて見て欲しい。

このソースコードを今までの2002や2003でビルドしても警告やエラーは出ない。
ところが2005(Express Editionも含む)はこんな警告を出す。

Gw20070919211002

英語は苦手なんだが、この関数(ここではsprintfとstrcpy)にはセキュリティに対応した新しい関数があるんでそっち使ってね…もしあれだったら_CRT_SECURE_NO_WARNINGSを有効にすればセキュリティ関係の警告は出さないようにするね…。ってことらしい。

セキュリティに対応したコードは大抵文句を言われた関数名に_sをつけたものらしい。
実際にやってみてビルドしてみる。

Gw20070919211243
こんな感じに警告は出なくなった。

セキュリティーコードってのはきっと転送先バッファあふれを防止することなんだと思う。
だからもし転送先バッファ以上のデータをコピーしたり、書き込んだりするとアサートでダイアログでも出して止まる仕組みにでもなってるんだろう。

そこでたぶん文句を言われるであろうソースコードに書き換える。

Gw20070919211839
ですよねぇ~

配列だとsizeofとかでサイズがわかるけど、mallocなんかで確保した動的な領域のサイズはわかんないわな。
じゃーそーするのかというとこうする。

Gw20070919212157
第2引数に転送先のバッファ量を指定する。

セキュリティーコード版の関数はオーバーロードされてこの2種類の引数が対応されているようだ(例外はあるかも)。

ところがこのコード、正直やってはこまることをやってくれる。
※私のプログラム作法が悪いのかもしれないが。

Gw20070919212651

デバック中のメモリ状態だ。
黄色い矢印の行を実行する寸前といったところでプログラムが停止している。
メモリ1のウィンドウの先頭がbuf1のアドレス。メモリ2がpBufだ。
両方の領域ともmemsetで0クリアされているのがわかるだろうか。

ここでsprintf_sでbuf1の領域に"abcdefg"という文字列を書き込む。
※文字列終端には当然\0(0x00)

Gw20070919212808

無事文字列が書き込まれているのがわかるが\0以降に注目してもらいたい。
0xfdがbuf1の残り領域いっぱいに書き込まれているのだ。

ということはstrcpy_sの方も…

Gw20070919212830
あぁぁぁ0xfdで犯されていくぅ・・・。汚れちゃったよぅぅぅぅ。僕の大切なメモリ空間がぁぁぁ。

マニュアルにはしっかりと第2引数は「転送先のバッファサイズ」とある。
くぅぅぅ。セキュリティが強固でもメモリを汚されるのはいやだなぁ…。

転送先のバッファサイズが最低こんだけ絶対あるの保障するよ~とかいってプログラマが確認の意味で第2引数を決め付けちゃうってんであれば

Gw20070919213014
こんな感じにしちゃって…

Gw20070919221208
ほらこのとおり…

ってだめじゃーーーん。
ちっともセキュリティコードじゃないよぅぅぅ。

もともとの私のプログラム作法が悪いのかしら?

ちなみに_sがついた関数はおそらく2002や2003にはないのでプリコンパイル時に切り替える仕組みを書くか、きっぱりセキュリティに対応した関数は使わないで_CRT_SECURE_NO_WARNINGSを有効にするべきだろう。

_CRT_SECURE_NO_WARNINGSを2005のときだけ簡単に有効にするには2005用のプロジェクトでソリューションエクスプローラからプロジェクトのプロパティを開いて(太字のプロジェクト名を右クリックしてのメニュー一番下)

Gw20070920112349_2

構成プルダウンメニューの「Debug」「Release」両方の構成に対して[構成プロパティ]-[C/C++]-[プリプロセッサ]の「プリプロセッサ定義」横にある[...]ボタンを押して_CRT_SECURE_NO_WARNINGSを追加すればOK。
いきなり「すべての構成」で設定してしまうともともと設定されている定義が消えちゃうようなので注意。

残ったメモリ空間を汚してしまうセキュリティコードってひどくないかぁ?
すでに大切な情報が書き込まれている場合とかも…きっと破壊するよねぇ…。
デバックビルドの時だけかとも思ったけど、実は別のプログラムのとき、リリースビルドでこれが原因で不具合が出たので、おんなじだろうと予想する。

私の根本的なプログラム作法を考え直すべきなんだろうか?

|

« XSI 6 Mod Tool - XNA 連携チュートリアル | トップページ | XSI 6 Mod Tool - XNA 連携チュートリアル(2) »

プログラミング」カテゴリの記事

プログラム」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/60500/16510127

この記事へのトラックバック一覧です: VC++ 2005 セキュリティーコード:

« XSI 6 Mod Tool - XNA 連携チュートリアル | トップページ | XSI 6 Mod Tool - XNA 連携チュートリアル(2) »