wcsncpy_s函数会导致缓冲区溢出吗?

Joh*_*ith 1 c++ buffer-overflow visual-c++

我试图了解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
Run Code Online (Sandbox Code Playgroud)

如果我理解这一切,"a",它应该最多包含4个宽字符和一个空终止符,现在可以容纳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);
Run Code Online (Sandbox Code Playgroud)

有人可以解释上面的代码,以及wcsncpy_s应该如何防止缓冲区溢出?

Jam*_*lis 6

wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);
Run Code Online (Sandbox Code Playgroud)

你是骗人的功能.你告诉它," a有足够的空间来存储10个字符",实际上它只有足够的空间来存储5个字符.该函数相信您正在为其提供有效信息(如何知道您不是?)

请注意,虽然第二个代码段出现运行时错误,但第一个代码段同样错误.两者都写过数组的末尾a.

这就是说:你正在使用错误的重载wcsncpy_s:在编译C++代码时,还有一个额外的wcsncpy_s重载是一个模板,可以推断出目标数组的大小.如果您要将呼叫更改为:

wcsncpy_s(a, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);
Run Code Online (Sandbox Code Playgroud)

模板将推断出该数组有五个元素,并自动将其用作大小.仅当目标是数组时才有效; 如果目标是指向数组中初始元素的指针,则它不起作用.

理想情况下,如果您使用的是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);
Run Code Online (Sandbox Code Playgroud)

代码std::vector<wchar_t>将是相同的.请注意,获取指向底层数组的指针并获取该数组的大小遵循相同的形式,因此编写代码很容易并且很容易检查代码是否正确(只需要对调用进行简单的目视检查) ).

  • @JohnSmith:“安全”的边界检查接口的目的不是在面对不正确的参数时保持安全,而是使函数具有尊重缓冲区边界所需的信息并提供以下功能:集中错误处理。 (2认同)