代码之家  ›  专栏  ›  技术社区  ›  Hamish Grubijan

使用wcsncpy复制字符串时缓冲区太小

  •  3
  • Hamish Grubijan  · 技术社区  · 15 年前

    这个C++代码有点蹩脚,但我需要维护它。我似乎找不出“缓冲区太小”的问题。我正在使用Visual Studio 2010。我将根据我在调试器中看到的值,提出复制所需的最少代码。抱歉,我不会测试实际的代码片段本身。另外,由于我的系统剪贴板在调试时“忙”,我不能只复制和粘贴,所以可能会有一些错误潜入某个地方,但我会仔细检查这些内容。相信我,你不想看到整个功能-它太长了,没有任何意义:)

    来自TCHAR

    #define _tcsncpy_s wcsncpy_s
    

    从AFXSTR。H:

    typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
    

    来自WiNT.H:

    typedef WCHAR TCHAR, *PTCHAR;
    

    哦,伙计,这些宏似乎永远不会结束。我将在这里停留。 最后,从myfile.cpp:

    CString str; // Actually a function parameter with value "07/02/2010"
    DWORD nIndex = 10;
    DWORD nLast = 0;
    LPCTSTR psz = (LPCTSTR) str; // Debugger says that it also gets "07/02/2010".
    
    CString s;
    _tcsncpy_s(
        s.GetBuffer((int) (nIndex - nLast + 1)), // I added the " + 1" part hoping to fix a bug, but that changed nothing
        nIndex - nLast,
        psz + nLast,
        (size_t) (nIndex - nLast)
    );
    

    有了这个,我找到了一个断言,调试器就打开了 tcsncpy_s.inl 结尾有以下代码:

      53    ...
      54    if (available == 0)
      55    {
      56        if (_COUNT == _TRUNCATE)
      57        {
      58            _DEST[_SIZE - 1] = 0;
      59            _RETURN_TRUNCATE;
      60        }
      61        RESET_STRING(_DEST, _SIZE);
    =>62        _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
      63    }
      64    _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
      65    _RETURN_NO_ERROR;
      66 }
      67
      68
    

    调试器指向第62行: _RETURN_BUFFER_TOO_SMALL . 不幸的是,在 TCSNCPy.S.IL . 也许有经验的编码员能告诉我这里发生了什么?我相信(也许是错误的)这段代码很旧,并且不是用Unicode编写的。解决这个问题的最佳方法是坚持旧的蹩脚枪(没有C++0X技巧或其他花哨的东西)-我只想给子弹伤口贴上补丁。

    3 回复  |  直到 15 年前
        1
  •  3
  •   Pavel Minaev    15 年前

    第四个论点 strncpy_s 是要从源缓冲区复制的字符数,它不考虑终止的空值——即,在实践中,如果源缓冲区包含 (nIndex - nLast) 或者多个字符,然后 (九度-最后一次) 将被复制,然后 将追加一个空字符。所以目标缓冲区必须准备接受 (nIndex - nLast + 1) 字符也可以解释该空值。

    现在你的+1看起来是这样的,但你也应该在第二个论点中反映出来 斯特朗皮亚 说明缓冲区有多大。把它改成 (九位数-最后一个+1) 它应该是有效的。

        2
  •  3
  •   Hans Passant    15 年前

    传递给wcsncpy_s()的大小是缓冲区大小,而不是缓冲区可以存储的字符数。它包括零终止符。您需要添加1。

        3
  •  2
  •   Michael Burr    15 年前

    从文档中 wcsncpy_s() ( http://msdn.microsoft.com/en-us/library/5dae5d43.aspx ):

    这些函数试图将strsource的前d个字符复制到strdest,其中d是count和strsource长度中的较小值。 如果这些d字符将适合strdest(其大小指定为numberofelements),并且仍为空终止符留有空间 ,然后复制这些字符并附加终止的空值;否则,strdest[0]设置为空值字符并调用无效的参数处理程序。

    因此,计数必须以字符(元素)而不是您已经在做的字节来指定,并且目标缓冲区的大小必须考虑到空终止符字符,您要在缓冲区中腾出空间,但不能告诉 WCSncPyIx() (称为 _tcsncpy() 这里:关于:

    _tcsncpy_s(
        s.GetBuffer((int) (nIndex - nLast + 1)), // I added the " + 1" part hoping to fix a bug, but that changed nothing
        nIndex - nLast + 1,
        psz + nLast,
        (size_t) (nIndex - nLast)
    );