3

我试图构建一个非常简约的内存读取库来读取一些unsigned ints。ReadUnsignedInt但是,当方法想要返回时,我遇到了“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

4 回答 4

4

Michael 和 Naveen 都在您的代码中发现了相同的主要缺陷,但不是唯一的缺陷。

shared_ptr当其引用计数变为零时,将delete指向对象。

这意味着您只能给它分配由 --not 分配的new对象new[]

您可能希望使用shared_ptr<vector<byte> >orboost::shared_array<byte>代替。

于 2009-10-14T16:51:22.847 回答
2

问题是:

new byte(numberOfBytes)

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

你想做:

new byte[numberOfBytes]    

它分配一个字节数组 numberOfBytes long。

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

于 2009-10-14T16:50:08.403 回答
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 几乎肯定会以内联函数的形式结束,因此所涉及的任何内容都不会真正“通过”或“返回”。

另一方面,这段代码在较旧的编译器上运行得不是特别好——而且对于足够旧的编译器,使用成员模板函数的版本甚至可能无法编译。但是,只要您使用合理的当前编译器,生活就应该是美好的。

于 2009-10-14T17:48:02.740 回答
0

我相信new byte(numberOfBytes)应该是new byte[numberOfBytes]。否则,您将只分配一个字节。只是为了完成答案,正如@ephemient 指出的那样,您不能在此处使用 shared_ptr ,因为它会执行delete您应该执行的操作delete[]。如果不这样做,行为将是未定义的。

于 2009-10-14T16:50:59.433 回答