VC ++ wcscpy_s随机断言“缓冲区太小”

时间:2019-11-09 13:48:27

标签: c++ windows visual-studio visual-c++

您可以从以下代码中看到发送给该函数的参数未超过缓冲区大小。

此问题是随机发生的,仅在调试版本中发生。

#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;
}

2 个答案:

答案 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);