無為空間
むいむい(´ω`*)
Entries
Visual Studio Team Editionのコード分析はそこそこ役に立つ機能ではあるが、一部APIにいい加減?な注釈が付いているため、意味の分からない警告を出すことがある。
#include <windows.h> void hoge() { if (HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4, 0)) { if (void* p = MapViewOfFile(h, FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, 0)) { memset(p, 0, 4);
上記コードでmemset()までたどり着くのは「4バイトのファイルマッピングオブジェクトを生成・マッピングできた」場合のみ。
それなのに、VS2005TEのコード分析は以下のような警告を出す。
(9) : warning C6386: バッファ オーバーランです: '引数 1' へアクセスしています。書き込み可能なサイズは '1*0' バイトですが、'4' バイトを書き込む可能性があります: Lines: 5, 7, 9
なぜ「書き込み可能なサイズは '1*0' バイト」と判定されているのか。
それはMapViewOfFile()の戻り値型「LPVOID」に「_out」の注釈が付いているからだ。
WINBASEAPI __out LPVOID WINAPI MapViewOfFile( __in HANDLE hFileMappingObject, __in DWORD dwDesiredAccess, __in DWORD dwFileOffsetHigh, __in DWORD dwFileOffsetLow, __in SIZE_T dwNumberOfBytesToMap );
サイズの指定のない「_out」注釈はバッファの長さが1要素分であることを示す。
戻り値型「LPVOID」の要素型は「void」なので、バッファの長さは「1*sizeof(void) = 1*0(便宜上)」バイトということになる。
void * __cdecl memset(__out_bcount_full_opt(_Size) void * _Dst, __in int _Val, __in size_t _Size);
それに対しmemset()の第1引数_Dstは「NULL以外のポインタを渡されたら(_opt)そのポインタが指す_Sizeバイトのバッファ(_bcount)全体を初期化する(_full)出力属性の引数(_out)」とある。
この2つの注釈を合わせて解釈すると、先の9行目のmemset()呼び出しは「4バイト初期化することを明言している引数に、バッファサイズが0バイトにしかならないMapViewOfFile()の戻り値なんかを渡している」ということになるので、コード分析が警告を出したのである。
このコード分析の判断自体に問題はない。
問題なのは「MapViewOfFile()の戻り値にこの_out注釈を付けている」こと。あるいは「サイズ指定なし=_ecount(1)」という仕様。そしてなによりC6386の解説を読んでも警告されている理由が分からないことである。
コメント
コメントの投稿
トラックバック
- トラックバック URL
- http://idlysphere.blog66.fc2.com/tb.php/231-fe1bdfe3
- この記事にトラックバックする(FC2ブログユーザー)