Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ wcsncpy_函数是否会导致缓冲区溢出?_C++_Visual C++_Buffer Overflow - Fatal编程技术网

C++ wcsncpy_函数是否会导致缓冲区溢出?

C++ wcsncpy_函数是否会导致缓冲区溢出?,c++,visual-c++,buffer-overflow,C++,Visual C++,Buffer Overflow,我试图了解wcsncpy_函数是如何工作的,以及它是如何防止缓冲区溢出的。首先,根据MSDN,此函数的参数表示以下内容: strDest=目标字符串 numberOfElements=目标字符串的大小 strSource=源字符串 count=要复制或截断的字符数 现在考虑这个代码: wchar_t a[5]; wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9); printf("%d\r\n", sizeof(a));//10 printf(

我试图了解wcsncpy_函数是如何工作的,以及它是如何防止缓冲区溢出的。首先,根据MSDN,此函数的参数表示以下内容:

strDest=目标字符串

numberOfElements=目标字符串的大小

strSource=源字符串

count=要复制或截断的字符数

现在考虑这个代码:

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
如果我理解了所有这些,“a”应该最多包含4个宽字符加上一个空终止符,现在可以包含9个宽字符

现在,由于调试断言失败(VS 2005编译器),以下代码将导致我的应用程序突然终止:

有人能解释一下上面的代码,以及wcsncpy_如何防止缓冲区溢出吗?

在这一行:

wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);
您告诉函数在
a
中有容纳
10个
字符的空间,而实际上只有容纳
5个
的空间

wcsncpy_s(a, 10, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);
你在对函数撒谎。你告诉它,“
a
有足够的空间存储10个字符”,而实际上它只有足够的空间存储5个字符。函数相信您正在向它提供有效信息(它怎么可能知道您没有呢?)

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

:你使用的是错误的超载:代码> WCSncPyys:编译C++代码时,有一个附加的<代码> WCSncPyys超载,它是一个推断目标数组大小的模板。如果您要将呼叫更改为:

wcsncpy_s(a, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 9);
模板将推断数组有五个元素,并自动将其用作大小。这仅在目标为数组时有效;如果目标是指向数组中初始元素的指针,则它不起作用

理想情况下,如果使用C++,最好避免C字符串操作:使用<代码> STD::WString 或其他字符串类型。如果您确实想使用这些与C字符串一起工作的函数,那么至少使用

std::vector
std::array
而不是原始数组:代码更难出错。比如说,

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

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

wcsncpy的定义是

errno_t wcsncpy_s(
wchar_t *strDest,
size_t numberOfElements,
const wchar_t *strSource,
size_t count 
);
strDest也是你写作的缓冲区

numberOfElements是strDest缓冲区中的元素数

strSource是您正在读取的缓冲区

count是strSource中要复制到strDest的元素数

所以在

wchar\u t的宽度为2个字符

问题是函数在结尾自动为您写入一个空终止符。这会导致溢出,因为它试图写入一个溢出


wcsncpy_没有帮助您解决此错误,因为您告诉它a中有10个元素可用。当实际上只有5个元素可用时。

+1:模板推断提供的重载对于编译时大小确定的固定大小缓冲区(即X[]的数组)非常有效。对于您自己分配的缓冲区,包括向量和字符串对象等stl序列,必须提供长度参数。编译器将告知何时,因为为目标提供非固定序列而不指定长度将生成编译器错误。James,第二个参数不应该表示目标缓冲区的大小吗?这就是MSDNsays@JohnSmith:否,第二个参数的名称是
numberOfElements
。元素的数量与
char
数组的大小相同(因为
sizeof(char)==1
),但对于
wchar\u t
(因为使用Visual C++时
sizeof(wchar\u t)==2
)不相同。但是,是的,违反任何运行时函数的先决条件都会导致程序产生未定义的行为。@JohnSmith:“安全”边界检查接口的目的不是在遇到错误参数时保持安全,这是为了使函数具有所需的信息,以尊重缓冲区边界,并提供集中错误处理的能力。
errno_t wcsncpy_s(
wchar_t *strDest,
size_t numberOfElements,
const wchar_t *strSource,
size_t count 
);
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);