删除[]时出现C ++ / CLI堆错误

时间:2014-06-23 18:09:28

标签: c++-cli

我似乎在删除char*数组时遇到问题。当delete[]被调用时,它会因堆损坏而崩溃:

typedef struct _CDB_SYMBOL_INFO {
    char *          name;
    unsigned long   address;
    unsigned long   value;
} CDB_SYMBOL_INFO;

// ...

    for each( Symbol ^ symbol in bls->Symbols )
    {
        CDB_SYMBOL_INFO symbol_info;

        symbol_info.name = new char[symbol->Name->Length];
        Marshal::Copy( symbol->Name->ToCharArray(), 0, IntPtr( (char*) symbol_info.name ), symbol->Name->Length );

        // see enumerate_cdb_symbols_callback(..)
        cdb_call_back(&symbol_info, *call_back);

        delete[] symbol_info.name; // Crashes here
    }

// ...

我在这里看不到问题..


static int enumerate_cdb_symbols_callback(CDB_SYMBOL_INFO * info, void * call_back)
{
    EnumerateSymbolsCallBack *cb = (EnumerateSymbolsCallBack*)call_back;

    Symbol * symbol = alloc_symbol();

    cb(0, symbol);

    return 0;
}

1 个答案:

答案 0 :(得分:3)

您为一个16位元素数组调用Marshal::Copy重载(.NET System::Char不是C ++ char!),第四个参数是数字元素不是字节数,因此您实际上复制symbol->Name->Length * 2个字节,这是缓冲区大小的两倍。产生的溢出会破坏堆元数据,导致delete[]崩溃。

使用wchar_t类型的缓冲区,它是匹配System::Char的C ++类型,或者将字符串转换为ASCII,可以将ToCharArray()替换为Encoding::ASCII::GetBytes(symbol->Name)。或UTF-8,在这种情况下,您不能假设symbol->Name->Length是必要的缓冲区大小。

更简单的方法是使用C ++ / CLI附带的marshal_as库:

#include <msclr\marshal_cppstd.h>
using namespace msclr::interop;

for each( Symbol ^ symbol in bls->Symbols )
{
    std::string sym_name = marshal_as<std::string>(symbol->Name);

    CDB_SYMBOL_INFO symbol_info;
    symbol_info.name = &sym_name[0];

    // see enumerate_cdb_symbols_callback(..)
    cdb_call_back(&symbol_info, *call_back);
}

它执行一些未指定的单字节字符编码(很可能是ASCII),并使用RAII自动释放内存。