为什么我会得到“双重自由或腐败”?

发布于 2025-01-03 20:30:45 字数 1193 浏览 0 评论 0原文

我正在尝试序列化一个结构,但程序崩溃了:

*** glibc detected *** ./unserialization: double free or corruption (fasttop): 0x0000000000cf8010 ***

#include <iostream>
#include <cstdlib>
#include <cstring>

struct Dummy
{
    std::string name;
    double height;
};

template<typename T>
class Serialization
{
    public:
        static unsigned char* toArray (T & t)
        {
            unsigned char *buffer = new unsigned char [ sizeof (T) ];
            memcpy ( buffer , &t , sizeof (T) );
            return buffer;
        };

        static T fromArray ( unsigned char *buffer )
        {
            T t;
            memcpy ( &t , buffer , sizeof (T) );
            return t;
        };
};

int main ( int argc , char **argv ) 
{
    Dummy human;
    human.name = "Someone";
    human.height = 11.333;

    unsigned char *buffer = Serialization<Dummy>::toArray (human);

    Dummy dummy = Serialization<Dummy>::fromArray (buffer);

    std::cout << "Name:" << dummy.name << "\n" << "Height:" << dummy.height << std::endl;

    delete buffer;

    return 0;
}

I am trying to serialize a struct, but the program crashed with:

*** glibc detected *** ./unserialization: double free or corruption (fasttop): 0x0000000000cf8010 ***

#include <iostream>
#include <cstdlib>
#include <cstring>

struct Dummy
{
    std::string name;
    double height;
};

template<typename T>
class Serialization
{
    public:
        static unsigned char* toArray (T & t)
        {
            unsigned char *buffer = new unsigned char [ sizeof (T) ];
            memcpy ( buffer , &t , sizeof (T) );
            return buffer;
        };

        static T fromArray ( unsigned char *buffer )
        {
            T t;
            memcpy ( &t , buffer , sizeof (T) );
            return t;
        };
};

int main ( int argc , char **argv ) 
{
    Dummy human;
    human.name = "Someone";
    human.height = 11.333;

    unsigned char *buffer = Serialization<Dummy>::toArray (human);

    Dummy dummy = Serialization<Dummy>::fromArray (buffer);

    std::cout << "Name:" << dummy.name << "\n" << "Height:" << dummy.height << std::endl;

    delete buffer;

    return 0;
}

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

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

发布评论

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

评论(4

无风消散 2025-01-10 20:30:45

我发现此代码有两个问题:

  1. 您通过将包含 std::stringstructmemcpy 转换为另一个来调用未定义的行为地点。如果您 memcpy 一个不仅仅是纯结构的类(例如 std::string),它可能会导致各种问题。在这种特殊情况下,我认为部分问题可能是 std::string 有时存储一个指向包含字符串实际内容的字符缓冲区的内部指针。如果您memcpy std::string,您就绕过了字符串的普通复制构造函数,该构造函数会复制该字符串。相反,您现在有两个不同的 std::string 实例共享一个指针,因此当它们被销毁时,它们都会尝试删除字符缓冲区,从而导致您看到的错误。除了不做你正在做的事情之外,没有简单的解决办法。这从根本上来说是不安全的。

  2. 您正在使用new[]分配内存,但使用delete删除它。您应该使用数组删除运算符delete[]来删除此内存,因为对其使用常规delete将导致未定义的行为,可能导致此崩溃。

希望这有帮助!

I see two problems with this code:

  1. You are invoking undefined behavior by memcpying a struct containing a std::string into another location. If you memcpy a class that isn't just a pure struct (for example, a std::string), it can cause all sorts of problems. In this particular case, I think that part of the problem might be that std::string sometimes stores an internal pointer to a buffer of characters containing the actual contents of the string. If you memcpy the std::string, you bypass the string's normal copy constructor that would duplicate the string. Instead, you now have two different instances of std::string sharing a pointer, so when they are destroyed they will both try to delete the character buffer, causing the bug you're seeing. There is no easy fix for this other than to not do what you're doing. It's just fundamentally unsafe.

  2. You are allocating memory with new[], but deleting it with delete. You should use the array deleting operator delete[] to delete this memory, since using regular delete on it will result in undefined behavior, potentially causing this crash.

Hope this helps!

孤寂小茶 2025-01-10 20:30:45

memcpy()std::string 类型的数据元素(或者实际上任何非 POD 数据类型)。 std::string 类将实际字符串数据存储在动态分配的缓冲区中。当您memcpy()周围的std::string内容时,您正在删除内部分配的指针并最终访问已经释放的内存。

您可以通过将声明更改为来使代码正常工作:

struct Dummy
{
    char name[100];
    double height;
};

但是,这具有固定大小 name 缓冲区的缺点。如果您想维护动态大小的 name,那么您将需要一个更复杂的 toArrayfromArray 实现,这些实现不能直接执行记忆副本。

It's not valid to use memcpy() with a data element of type std::string (or really, any non-POD data type). The std::string class stores the actual string data in a dynamically-allocated buffer. When you memcpy() the contents of a std::string around, you are obliterating the pointers allocated internally and end up accessing memory that has been already freed.

You could make your code work by changing the declaration to:

struct Dummy
{
    char name[100];
    double height;
};

However, that has the disadvantages of a fixed size name buffer. If you want to maintain a dynamically sized name, then you will need to have a more sophisticated toArray and fromArray implementation that doesn't do straight memory copies.

赤濁 2025-01-10 20:30:45

您将在 toArray 调用中复制 string 的内部缓冲区。当使用 fromArray 反序列化时,您在 dummy 中“创建”第二个字符串,它认为它拥有与 human 相同的缓冲区。

You're copying the string's internal buffer in the toArray call. When deserializing with fromArray you "create" a second string in dummy, which thinks it owns the same buffer as human.

柒七 2025-01-10 20:30:45

std::string 可能包含一个指向包含字符串数据的缓冲区的指针。当您调用 toArray ( human) 时,您正在 memcpy() 处理 Dummy 类的字符串,包括指向字符串数据的指针。然后,当您通过直接 memcpy() 创建一个新的虚拟对象时,您就创建了一个新的字符串对象,该对象具有与第一个对象相同的指向字符串数据的指针。接下来你知道,dummy 被破坏,指针的副本被破坏,然后 human 被破坏,然后 BAM,你得到了双重释放。

一般来说,像这样使用 memcpy 复制对象会导致各种各样的问题,就像您所看到的那样。这可能只是冰山一角。相反,您可能会考虑为要序列化的每个类显式实现某种编组函数。

或者,您可以查看 C++ 的 json 库,它可以将事物序列化为方便的基于文本的格式。 JSON 协议通常与您想要序列化对象以通过套接字发送的自定义网络协议一起使用。

std::string probably contains a pointer to a buffer that contains the string data. When you call toArray (human), you're memcpy()'ing the Dummy class's string, including the pointer to the string's data. Then when you create a new Dummy object by memcpy()'ing directly into it, you've created a new string object with the same pointer to string data as the first object. Next thing you know, dummy gets destructed and the copy of the pointer gets destroyed, then human gets destructed and BAM, you got a double free.

Generally, copying objects using memcpy like this will lead to all sorts of problems, like the one you've seen. Its probably just going to be the tip of the ice berg. Instead, you might consider explicitly implementing some sort of marshalling function for each class you want to serialize.

Alternatively, you might look into json libraries for c++, which can serialize things into a convenient text based format. JSON protocols are commonly used with custom network protocols where you want to serialize objects to send over a socket.

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