如何修复堆损坏

时间:2009-10-14 16:45:43

标签: c++ shared-ptr raii

我试图建立一个非常简约的内存读取库来读取它的一些unsigned int。但是,当ReadUnsignedInt方法想要返回时,我遇到了“HEAP CORRUPTION DETECTED”错误消息。

  

HEAP CORRUPTION DETECTED。 CRT检测到应用程序在缓冲区结束后写入内存。

正如我所读到的,这可能是尝试双重删除某些内容时的原因。这可能是由std::tr1::shared_ptr的一些错误使用引起的,但我无法确定我对它们做错了什么。代码如下(省略错误处理):

unsigned int Memory::ReadUnsignedInt (unsigned int address) const {
    std::tr1::shared_ptr<byte> bytes = 
        this->ReadBytes(address, sizeof(unsigned int));
    return *((int*)bytes.get());
    // correct value (how to improve this ugly piece of code?)
}

std::tr1::shared_ptr<byte> Memory::ReadBytes (
    unsigned int address, int numberOfBytes) const
{
    std::tr1::shared_ptr<byte> pBuffer(new byte(numberOfBytes));
    ReadProcessMemory(m_hProcess.get(), (LPCVOID)address, 
        pBuffer.get(), numberOfBytes * sizeof(byte), NULL))
    return pBuffer;
}

4 个答案:

答案 0 :(得分:4)

Michael和Naveen都发现了代码中的主要缺陷,但并非唯一的缺陷。

当引用计数为零时,

shared_ptrdelete指向对象。

这意味着您只能为new分配的对象提供 - 而不是new[]

您可能希望改为使用shared_ptr<vector<byte> >boost::shared_array<byte>

答案 1 :(得分:2)

问题是:

new byte(numberOfBytes)

这将分配一个值为numberOfBytes的单个字节。

你想这样做:

new byte[numberOfBytes]    

分配一个字节数组numberOfBytes long。

但是既然你知道你只读了4个字节,为什么还要分配内存呢?只需传递堆栈中unsigned int的地址即可。

答案 2 :(得分:2)

已经指出了代码的基本问题。看着它,我想知道你为什么要在这里使用shared_ptr。如果我这样做,我可能会使用这样的东西:

unsigned Memory::ReadUnsignedInt(unsigned address) { 
    unsigned ret;
    ReadProcessMemory(m_hProcess.get(), (void *)address, &ret, sizeof(ret), NULL);
    return ret;
}

std::vector<char> Memory::ReadBytes(unsigned address, int num) { 
    std::vector<char> ret(num);
    ReadProcessMemory(m_hProcess.get(), (void *)address, &ret[0], num, NULL);
    return ret;
}

然后再次使用模板而不是ReadUnsignedInt:

template <class T>
T Memory::Read(unsigned address) { 
    T ret;
    ReadProcessMemory(m_hProcess.get(), (void*)address, &ret, sizeof(ret), NULL);
    return ret;
}

由于您没有传递可以推导出模板参数类型的参数,因此您必须明确指定:

int x = Read<int>(wherever);
char a = Read<char>(wherever);

另一种方法是将目的地作为参数传递:

template <class T>
Memory::Read(unsigned address, T &t) { 
    ReadProcessMemory(my_hProcess.get(), (void *)address, &t, sizeof(t), NULL);
};

你可以使用:

Read(wherever, some_int);
Read(somewhere, some_long);

等等。

如果你担心返回char向量的效率低下,你可能不应该 - VC ++(像大多数其他合理的当前编译器一样)具有所谓的“命名返回值优化”,这意味着在某种情况下像这样,它会将一个隐藏的引用传递给你分配结果的向量,而ReadBytes将使用它直接将数据存放到最终结束的位置。就此而言,在任何合理的优化开启的情况下,ReadBytes几乎肯定会最终成为一个内联函数,所以任何涉及的东西都不会被“传递”或“返回”。

另一方面,对于较旧的编译器,此代码将无法正常工作 - 并且使用足够多的编译器,使用成员模板函数的版本可能甚至无法编译。但是,只要您使用合理的当前编译器,生活就应该很好。

答案 3 :(得分:0)

我相信new byte(numberOfBytes)应为new byte[numberOfBytes]。否则你只会分配一个字节。只是为了完成答案,因为@ephemient表示你不能在这里使用shared_ptr,因为它会delete执行delete[]。如果不这样做,行为将是未定义的。