如何修复堆损坏

发布于 2024-08-08 15:25:15 字数 910 浏览 3 评论 0 原文

我尝试构建一个非常简约的内存读取库来从中读取一些unsigned int。但是,当 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;
}

I've tried to build a very minimalistic memory read library to read some unsigned ints out of it. However, I run into a "HEAP CORRUPTION DETECTED" error message when the ReadUnsignedInt method wants to return.

HEAP CORRUPTION DETECTED. CRT detected that the application wrote to memory after end of buffer.

As I have read, this may be the cause when trying to double delete something. This may be caused by some incorrect usage of the std::tr1::shared_ptr but I cannot determine what I am doing wrong with them. Code is as follows (error handling omitted):

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

就像说晚安 2024-08-15 15:25:15

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

当引用计数为零时,shared_ptr删除所指向的对象。

这意味着您只能给它由 new 分配的对象,而不是 new[]

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

Michael and Naveen have both found the same major flaw in your code, but not the only flaw.

shared_ptr will delete the pointed-at object when its reference count goes to zero.

This means you can only give it objects allocated by new -- not new[].

You may wish to use shared_ptr<vector<byte> > or boost::shared_array<byte> instead.

青衫负雪 2024-08-15 15:25:15

问题是:

new byte(numberOfBytes)

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

您想要执行的操作:

new byte[numberOfBytes]    

分配一个字节数组 numberOfBytes long。

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

The issue is:

new byte(numberOfBytes)

This allocates a single byte with a value of numberOfBytes.

You want to do:

new byte[numberOfBytes]    

Which allocates an array of bytes numberOfBytes long.

But since you know you are only reading 4 bytes, why bother allocating memory at all? Just pass the address of a unsigned int on the stack.

要走干脆点 2024-08-15 15:25:15

已经指出了代码的基本问题。看着它,我想知道为什么你要在这里使用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 几乎肯定会最终成为内联函数,因此所涉及的任何内容都不会真正被“传递”或“返回”。

另一方面,这段代码在较旧的编译器中工作得不太好——并且在足够旧的编译器中,使用成员模板函数的版本甚至可能无法编译。然而,只要您使用最新的编译器,生活应该会很好。

The basic problems with your code have been pointed out already. Looking at it, I'm left wondering why you'd use a shared_ptr here at all, though. If I were doing it, I'd probably use something like this:

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;
}

Then again, instead of ReadUnsignedInt, I'd be tempted to use a template:

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

Since you don't pass a parameter from which it can deduce the type for the template parameter, you'd always have to specify explicitly:

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

The alternative would be to pass the destination as a parameter:

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

which you'd use like:

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

and so on.

If you're worried about the inefficiency of returning a vector of char, you probably shouldn't -- VC++ (like most other reasonably current compilers) has what's called a "named return value optimization", which means in a situation like this, it passes a hidden reference to the vector you assign the result to, and ReadBytes will use that to deposit the data directly where it's going to end up anyway. For that matter, with any reasonable optimization turned on at all, ReadBytes will almost certainly end up as an inline function, so nothing involved really gets "passed" or "returned" at all.

On the other hand, this code won't work particularly well with older compilers -- and with old enough compilers, the versions using member template functions probably won't even compile. As long as you use a reasonably current compiler, however, life should be good.

隐诗 2024-08-15 15:25:15

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

I believe new byte(numberOfBytes) should be new byte[numberOfBytes]. Otherwise you would have allocated only one byte. Just to complete the answer, as @ephemient indicated you can not use shared_ptr here as it will do a delete where as you should do delete[]. If not done like this, the behavior will be undefined.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文