【问题标题】:Deleting wchar_t* cause heap corruption删除 wchar_t* 导致堆损坏
【发布时间】:2014-05-19 09:41:32
【问题描述】:

我有这部分代码:

class CNuovoVocabolo {
    CString m_strItaliano;
    CString m_strRusso;
    //...
}

void CNuovoVocabolo::GetVocabolo( CVocabolo* pVocabolo )
{
    int nLIta;
    int nLRus;
    wchar_t *pIta;
    wchar_t *pRus;

    nLIta = m_strItaliano.GetLength();
    nLRus = m_strRusso.GetLength();
    if( nLIta > 0 && nLRus > 0 )
    {
        pIta = new wchar_t[nLIta + 1];
        wcscpy_s( pIta, nLIta * sizeof( wchar_t ), m_strItaliano );
        pRus = new wchar_t[nLRus + 1];
        wcscpy_s( pRus, nLRus * sizeof( wchar_t ), m_strRusso );
        pVocabolo->SetVocabolo( pIta, nLIta, pRus, nLRus );
        delete [] pIta; // *1
        delete [] pRus; // *2
    }
}

// Inside CVocabolo::SetVocabolo:
void CVocabolo::SetVocabolo( const wchar_t* pIta/*=NULL*/, unsigned short nLIta/*=0*/, const wchar_t* pRus/*=NULL*/, unsigned short nLRus/*=0*/ )
{
    if( pIta != NULL && pRus != NULL && nLIta > 0 && nLRus > 0 )
    {
        AzzeraVocabolo();
        m_nLIta = nLIta;
        m_nLRus = nLRus;
        m_pItaliano = new wchar_t[nLIta + 1];
        wcscpy_s( m_pItaliano, nLIta * sizeof( wchar_t ), pIta );
        m_pRusso = new wchar_t[nLRus + 1];
        wcscpy_s( m_pRusso, nLRus * sizeof( wchar_t ), pRus );
    }
}

当我删除 *1 和 *2 处的 pIta 指针和 pRus 指针时,由于堆损坏而崩溃。老实说,我不明白为什么会发生这种情况以及我做错了什么。有什么建议吗?

编辑:
上网查了一下,找到了解决办法:

pIta = new wchar_t[( nLIta + 1 ) * sizeof( wchar_t )];

但老实说,我还不清楚。如果你能给我一个解释... 另外,知道这个问题为什么被否决也很好。

【问题讨论】:

  • wcscpy_s 看起来很可疑,尤其是乘以 sizeof (wchar_t)。
  • 一个好的开始是停止在堆上使用指针和动态分配,并开始使用std::wstring。
  • wcs_cpy_s 的秒参数是 numberOfElements,而不是字节。所以不需要乘法。
  • @ivangrynko 不使用 * sizeof( wchar_t ) 会导致 Buffer too small 异常。

标签: c++ mfc heap-corruption


【解决方案1】:

问题就在这里。

pIta = new wchar_t[nLIta + 1];
wcscpy_s( pIta, nLIta * sizeof( wchar_t ), m_strItaliano );

在第一行中,大小是一个宽字符数组加上一个空终止符。这是正确的。

在第二行中,所需的大小也是字符数加上 null,但是您通过乘法给了它一个更大的数字。这是错误的。

如果这些是 short 字符和 20 个字符的字符串,则第一个参数是 21,第二个参数是 40(也应该是 21)。这本身就是一个无声的错误。不幸的是,在 DEBUG 构建(我假设您正在使用)中,wcscpy_s 函数填充了整个缓冲区,巧妙地覆盖了未分配的内存。

您的修复工作有效的原因是您(错误地)使缓冲区足够大以容纳(错误的)长度副本,并且两个 wongs 变成了白色(哎呀!)。

修复1:去掉sizeof的乘法,null加1。

修复 2:停止使用这些可怕的函数,开始使用 wstring 等编写一些好的 C++。

编辑:允许目的地为空。 (哎呀)

【讨论】:

  • 这些函数的“安全”变体如何导致缓冲区溢出也很有趣。
  • 好吧,我尝试删除 wcscpy_s 中的 * sizeof( wchar_t ) 但这会导致“缓冲区太小”错误。那我应该如何解决这个错误呢?
  • 对不起,您需要允许为空(见编辑)。但是您可以通过查看 MSDN 文档轻松找到与我相同的方法。
  • @rubenvb:如果您查看 MS 文档,这些是不是当前的安全变体。 MS 提供了可避免这些问题的模板化安全变体。
  • @david.pfx 如果我没记错的话,C11 Annex K 安全 CRT 功能是在 MS 实现之后建模的(这是标准化时唯一的一个)。不过我可能错了……
猜你喜欢
  • 1970-01-01
  • 2013-04-15
  • 2010-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多