您可以从以下代码中看到发送给该函数的参数未超过缓冲区大小。
此问题是随机发生的,仅在调试版本中发生。
#include <thread>
#include <sstream>
#define BUF_SZ 32
int main()
{
wchar_t src[BUF_SZ]{};
bool running = true;
std::thread th([&] {
for (double g = 0; g < 100000; g += .1)
{
std::wstringstream ws;
ws << g;
wcscpy_s(src, BUF_SZ, ws.str().c_str());
}
running = false;
});
wchar_t dst[BUF_SZ]{};
while (running)
wcscpy_s(dst, src); // assert on "Buffer is too small" randomly
th.join();
return 0;
}
答案 0 :(得分:1)
感谢MSFT VC ++团队的Steve Wishnousky先生,这里是问题的完整解释。
Wcscpy_s不能在缓冲区上自动运行,而只能工作 如果缓冲区在运行期间未更改内容,则正确 wcscpy_s。
要注意的另一件事是,在调试模式下,wcscpy_s函数 将用调试标记(0xFE)填充缓冲区的其余部分,以 指示那里的数据现在无效以假定其内容, 为了检测潜在的运行时错误。
当然每次错误都会以不同的方式发生,但是让我们假设 当src = 1269.9并调用wcscpy_s(dst,src)时,会发生此错误。 src的实际内容是:“ 1 2 6 9。9 null 0xfe 0xfe ...”。 wcscpy_s复制了1269.9以上的内容,但由于它将要读取null, 另一个wcscpy_s只是向src写了一个新值,所以现在是:“ 1 2 7 0 null 0xfe 0xfe ...“。而不是从读取对应的null 上一个src,它读取0xfe,因此认为这是真实的 字符。由于没有空终止符,直到我们到达末尾 缓冲区,调试运行时断言缓冲区太小 输入。
在Release版本中,0xFE调试标记未放置在 缓冲区,因此它将最终找到一个空字符。你也可以 通过调用_CrtSetDebugFillThreshold禁用调试标记: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/crtsetdebugfillthreshold?view=vs-2019。
请注意,调试标记实际上正在捕获真正的正确性 问题在这里。此“在wcscpy_s期间更改了缓冲区”的问题可能 发生任何价值。例如,如果src = 1269.9,则wcscpy_s可以复制 超过126,但随后将要读取9,则src更新为 1270,最终以dest结尾的值为“ 1260”。
答案 1 :(得分:0)
由于字符串复制将需要复制“ src”字符和终止的空字符,因此您需要提供至少比sizeof“ src”大一个字符的缓冲区。
我建议您可以尝试使用:
wcscpy_s(dst, sizeof src+1, src);