【问题标题】:crash after memcpy: access violation reading locationmemcpy 后崩溃:访问冲突读取位置
【发布时间】:2014-12-25 00:27:24
【问题描述】:
if (m_Connections[t].socket != INVALID_SOCKET)
{
    m_TCPResult = recv(m_Connections[t].socket, m_TCPRecvbuf, m_TCPRecvbuflen, 0);

    if (m_TCPResult > 0)
    {
        printf("[TCPReceive] Bytes (m_TCPResult) received from %d: %d\n", m_Connections[t].socket, m_TCPResult);

        // Deserialize the data
        Packets::MainPacket receivedData;
        memcpy(&receivedData, m_TCPRecvbuf, sizeof(receivedData));

        // Check the type and do something with the data
        CheckType(m_Connections[t].socket, receivedData);
    }
    else  
    {
        if (WSAGetLastError() != WSAEWOULDBLOCK)
            printf("TCPReceive error: %d\n", WSAGetLastError());
    }
}

所以我有这段代码。我需要做一个 memcpy() 来将传入的数据从 winsock 转换为应用程序可以读取的结构。但是,在 CheckType() 方法完成后,应用程序崩溃给我一个访问冲突读取位置错误。我删除了一次 memcpy() 方法进行检查,然后它工作正常(没有崩溃)。

我不知道问题可能是什么。我一直在 Google 上搜索,但没有发现任何有用的东西似乎可以解决我的问题

编辑:

更多信息:

// in the header
char m_TCPRecvbuf[DEFAULT_BUFLEN];

// receivedData struct
struct MainPacket
{
    char type;
    int id;

    LoginData loginData;
    vector<PlayerData> playerData;
};

【问题讨论】:

  • 如果答案是“在头文件中”,它们是如何定义的? memcpy 到一个未知的数据结构看起来非常可疑。
  • CheckType 包含什么?
  • 我用更多数据编辑了主要问题
  • CheckType 是一个简单的开关,它根据结构的类型执行某些操作(请参阅问题中的定义)
  • 不应该像memcpy(&receivedData, m_TCPRecvbuf, sizeof(m_TCPRecvbuf));

标签: c++ memcpy


【解决方案1】:

当你写你的memcpy 时,你写的是vector。它不是POD,你不能通过memcpy来初始化它,而是必须使用它的成员函数来初始化它。

这样想,vector 将至少有一个指向它管理的数据的指针和一个 size_t 指示大小。你不能仅仅通过memcpying 一个你通过网络收到的值来初始化指针。该指针可能对发送者有意义,但是当您收到它时,您所拥有的只是一个在服务器上有效的指针,而不是在您的应用程序中。因此,当您尝试使用 vector 时,您将得到未定义的行为,并且可能会崩溃(如果幸运的话)。

此外,由于 sizeof 不能以您在应用于类时所期望的方式工作。例如,如果您的 vector 包含 1,000 个项目,则 sizeof 不会反映这一点。 sizeof 告诉您的是类定义中所有成员变量的组合大小(取决于填充)。如果我们的vector 实现只是一个指针和一个size_t,那么在 32 位平台上它可能大约为 8 个字节,在 64 位平台上为 16 个字节,无论向量中有多少项。

您需要做的是对数据包中的信息进行编码,以便您可以对其进行解码。例如,您的数据包不应发送vector,而是应包含一个指示PlayerData 实例数量的字段,然后是每个玩家的数据。

【讨论】:

  • 那么可能的 PlayerData 的数据还能在向量中吗?
  • @Dries - 您可以将数据存储在 vector 中,但您不能将 memcpy 存储在其中。您将需要一个稍微详细的网络数据包结构,您可以将其分开并用于初始化数据。你不能做的只是通过网络发送构成MainPacket 的字节并期望它们在接收器上有意义。
  • 好的,我想我明白了。我将添加一个新字段,其中包含您所说的许多 playerData 对象。然后我是否只做一个 for 循环并填写新向量?我想只要我有对象的数量和每个对象的大小,这应该可以工作?
  • 您还需要查看如何序列化 PlayerData 类型。如果它有课程,那么你必须应用相同的规则。这意味着你的网络数据包的大小会有所不同,所以通常的做法是在网络数据包的开头有一个字段,指示数据包有多少字节组成,这样你就可以正确读取数据包。
  • PlayerData 当前持有另一个自定义结构(用于持有 2d 位置)。该死的,这可能比我想的要难得多。你有可能在某个地方举个例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2016-05-28
  • 2017-01-09
相关资源
最近更新 更多