2

wcsncpy_s関数がどのように機能し、バッファオーバーフローを防ぐ方法を理解しようとしています。まず、MSDNによると、この関数の引数は次のことを意味します。

strDest=宛先文字列。

numberOfElements=宛先文字列のサイズ。

strSource=ソース文字列。

count =コピーする文字数、または_TRUNCATE。

ここで、このコードについて考えてみましょう。

wchar_t a[5];
wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);

printf("%d\r\n", sizeof(a));//10
printf("%d\r\n", wcslen(a));//9
wprintf(L"%s", a);//ABCDEFGHI

これらすべてを理解すると、最大4つのワイド文字とヌルターミネータを保持することになっている「a」は、現在9つのワイド文字を保持します。

次のコードにより、デバッグアサーション(VS 2005コンパイラ)が失敗したためにアプリが突然終了します。

wchar_t a[5];
wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10);

printf("%d\r\n", sizeof(a));
printf("%d\r\n", wcslen(a));
wprintf(L"%s", a);

誰かが上記のコードと、wcsncpy_sがバッファオーバーフローを防ぐためにどのように想定されているかを説明できますか?

4

3 に答える 3

8
wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);

あなたはその機能に嘘をついています。a実際には5文字を格納するのに十分なスペースしかないのに、「10文字を格納するのに十分なスペースがある」と言います。関数は、あなたが有効な情報を提供していることを信頼します(あなたがそうではないことをどうやって知ることができますか?)

2番目のコードスニペットでランタイムエラーが発生する一方で、最初のコードスニペットも同様に間違っていることに注意してください。どちらも配列の終わりを超えて書き込みaます。

wcsncpy_sつまり、C ++コードをコンパイルするときに、間違ったオーバーロードを使用している場合wcsncpy_s、ターゲット配列のサイズを推測するテンプレートである追加のオーバーロードがあります。呼び出しを次のように変更する場合:

wcsncpy_s(a, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);

テンプレートは、配列に5つの要素があると推測し、それをサイズとして自動的に使用します。これは、ターゲットが配列の場合にのみ機能します。ターゲットが配列の最初の要素へのポインタである場合は機能しません。

理想的には、C ++を使用している場合は、C文字列の操作を完全に回避することをお勧めしますstd::wstring 。または他の文字列型を使用します。C文字列で機能するこれらの関数を使用する場合は、少なくとも生の配列を使用するstd::vector<wchar_t>か、std::array<wchar_t, N>代わりに使用します。コードを台無しにするのははるかに困難です。例えば、

std::array<wchar_t, 5> a;
wcsncpy_s(a.data(), a.size(), L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);

のコードはstd::vector<wchar_t>同じです。基になる配列へのポインターの取得とその配列のサイズの取得は同じ形式に従うため、コードの記述とコードが正しいことの確認の両方が簡単であることに注意してください(必要なのは呼び出しの単純な視覚的検査だけです)。 )。

于 2012-09-28T17:18:30.793 に答える
4

この行で:

wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);

実際には。の余地しかないのに、に10文字の余地があることを関数に伝えています。a5

于 2012-09-28T17:17:28.817 に答える
2

wcsncpy_sの定義は次のとおりです。

errno_t wcsncpy_s(
wchar_t *strDest,
size_t numberOfElements,
const wchar_t *strSource,
size_t count 
);

strDestは、書き込みのバッファでもあります。

numberOfElementsは、strDestバッファー内にある要素の数です。

strSourceは、読み取り元のバッファーです。

countは、strDestにコピーするstrSource内の要素の数です。

だからで

wchar_t a[5];
wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10); //ERROR

printf("%d\r\n", sizeof(a));
printf("%d\r\n", wcslen(a));
wprintf(L"%s", a);

wchar_tの幅は2文字です。

問題は、関数が最後にnullターミネータを自動的に書き込むことです。これによりオーバーフローが発生し、最後を超えて1つ書き込もうとします。

wcsncpy_sは、で使用可能な要素が10個あると言ったため、このエラーの解決には役立ちません。実際に利用できる要素が5つしかない場合。

于 2012-09-28T17:24:11.967 に答える