微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

更改为 std::vector 导致分段错误

如何解决更改为 std::vector 导致分段错误

你好,我有一个使用 new 关键字分配内存的结构,我想使用 std::vector 删除,所以我喜欢这个

在更改为 std::vector 之前

BYTE* packPlayerMoving(PlayerMoving* dataStruct)
{
    BYTE* data = new BYTE[56];
    for (int i = 0; i < 56; i++)
    {
        data[i] = 0;
    }
    memcpy(data,&dataStruct->packetType,4);
    memcpy(data + 4,&dataStruct->netID,4);
    memcpy(data + 12,&dataStruct->characterState,4);
    memcpy(data + 20,&dataStruct->plantingTree,4);
    memcpy(data + 24,&dataStruct->x,4);
    memcpy(data + 28,&dataStruct->y,4);
    memcpy(data + 32,&dataStruct->XSpeed,4);
    memcpy(data + 36,&dataStruct->YSpeed,4);
    memcpy(data + 44,&dataStruct->punchX,4);
    memcpy(data + 48,&dataStruct->punchY,4);
    return data;
}
void SendPacketRaw(int a1,void *packetData,size_t packetDataSize,void *a4,ENetPeer* peer,int packetFlag)
{
    ENetPacket *p;

    if (peer) // check if we have it setup
    {
        if (a1 == 4 && *((BYTE *)packetData + 12) & 8)
        {
            p = enet_packet_create(0,packetDataSize + *((DWORD *)packetData + 13) + 5,packetFlag);
            int four = 4;
            memcpy(p->data,&four,4);
            memcpy((char *)p->data + 4,packetData,packetDataSize);
            memcpy((char *)p->data + packetDataSize + 4,a4,*((DWORD *)packetData + 13));
            enet_peer_send(peer,p);
        }
        else
        {
            p = enet_packet_create(0,packetDataSize + 5,packetFlag);
            memcpy(p->data,&a1,packetDataSize);
            enet_peer_send(peer,p);
        }
    }
    delete (char*)packetData;
}

更改为 std::vector 后

std::vector<BYTE> packPlayerMoving(PlayerMoving *dataStruct)
{
    std::vector<BYTE> data(56);
    memcpy(&data[0],4);
    memcpy(&data[4],4);
    memcpy(&data[12],4);
    memcpy(&data[20],4);
    memcpy(&data[24],4);
    memcpy(&data[28],4);
    memcpy(&data[32],4);
    memcpy(&data[36],4);
    memcpy(&data[44],4);
    memcpy(&data[48],std::vector<BYTE> packetData,ENetPeer *peer,int packetFlag)
{
    ENetPacket *p;

    if (peer) // check if we have it setup
    {
        if (a1 == 4 && *(&packetData[12]) & 8)
        {
            p = enet_packet_create(0,packetDataSize + *(&packetData[13]) + 5,&packetData[0],packetDataSize);
            void * a4 = 0;
            memcpy((char *)p->data + packetDataSize + 4,*(&packetData[13]));
            enet_peer_send(peer,p);
        }
    }
}

我是这样使用的:

SendPacketRaw(4,packPlayerMoving(&data),56,currentPeer,ENET_PACKET_FLAG_RELIABLE);

好的,所以我的问题是在我将它转换为 std::vector 之前它工作正常没有问题 但是在我转换它之后我开始出现分段错误我做错了什么?

这里是valgrind输出

==12418== Conditional jump or move depends on uninitialised value(s)
==12418==    at 0x1189D7: SendPacketRaw(int,std::vector<unsigned char,std::allocator<unsigned char> >,unsigned long,void*,_ENetPeer*,int) (utils.cpp:172)
==12418==    by 0x11E337: nothing(_ENetPeer*,int,int) (worlds.cpp:405)
==12418==    by 0x1208AD: Events::Recieve(_ENetHost*,_ENetPacket*,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418== 
==12418== Conditional jump or move depends on uninitialised value(s)
==12418==    at 0x1450E7: enet_packet_create (in /home/cmd/Desktop/PRC++/server)
==12418==    by 0x118A20: SendPacketRaw(int,int) (utils.cpp:174)
==12418==    by 0x11E337: nothing(_ENetPeer*,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418== 
==12418== Conditional jump or move depends on uninitialised value(s)
==12418==    at 0x48429FA: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12418==    by 0x118AA8: SendPacketRaw(int,int) (utils.cpp:179)
==12418==    by 0x11E337: nothing(_ENetPeer*,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418== 
==12418== Conditional jump or move depends on uninitialised value(s)
==12418==    at 0x4842BA1: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12418==    by 0x118AA8: SendPacketRaw(int,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418== 
==12418== Conditional jump or move depends on uninitialised value(s)
==12418==    at 0x4842B0E: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12418==    by 0x118AA8: SendPacketRaw(int,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418== 
==12418== Invalid read of size 2
==12418==    at 0x4842B30: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12418==    by 0x118AA8: SendPacketRaw(int,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418==  Address 0x0 is not stack'd,malloc'd or (recently) free'd
==12418== 
==12418== 
==12418== Process terminating with default action of signal 11 (SIGSEGV)
==12418==  Access not within mapped region at address 0x0
==12418==    at 0x4842B30: memmove (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==12418==    by 0x118AA8: SendPacketRaw(int,std::allocator<char> >) (events.cpp:315)
==12418==    by 0x123BDB: Run() (main.cpp:62)
==12418==    by 0x123C85: main (main.cpp:87)
==12418==  If you believe this happened as a result of a stack
==12418==  overflow in your program's main thread (unlikely but
==12418==  possible),you can try to increase the size of the
==12418==  main thread stack using the --main-stacksize= flag.
==12418==  The main thread stack size used in this run was 8388608.
==12418== 
==12418== HEAP SUMMARY:
==12418==     in use at exit: 11,557,918 bytes in 22,893 blocks
==12418==   total heap usage: 94,578 allocs,71,685 frees,29,567,151 bytes allocated
==12418== 
==12418== LEAK SUMMARY:
==12418==    definitely lost: 1,312 bytes in 4 blocks
==12418==    indirectly lost: 5,711 bytes in 17 blocks
==12418==      possibly lost: 224 bytes in 2 blocks
==12418==    still reachable: 11,550,671 bytes in 22,870 blocks
==12418==         suppressed: 0 bytes in 0 blocks
==12418== Rerun with --leak-check=full to see details of leaked memory
==12418== 
==12418== Use --track-origins=yes to see where uninitialised values come from
==12418== For lists of detected and suppressed errors,rerun with: -s
==12418== ERROR SUMMARY: 45563 errors from 34 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

解决方法

*((DWORD *)packetData + 13) 在您的第一个版本中读取第 13 个 DWORD(在字节索引 52 处)。

*(&packetData[13]) 在您的第二个版本中读取第 13 个字节。

这整个代码有点乱,所以我不想把这个问题写下来,但把第二个版本改成:

*(((DWORD *)packetData.data())+13) 应该修复它。

,

在您的原始代码中,在您的 SendPacketRaw() 函数中,您删除了传递给它的 packetData 指针参数,而在此修改版本中,第二个参数 packetData 是一个在函数 SendPacketRaw() 结束后继续保存一些数据的向量。

我不确定您的 SendPacketRaw() 函数的使用以及管理其第二个参数应该维护的内存的逻辑,但我有一种直觉,这是 Valgrind 的主要原因不开心。

因此,我建议您首先将第二个向量参数 packetData 作为参考传递,并在完成函数之前对其进行清理。

void SendPacketRaw(int a1,std::vector<BYTE> &packetData,size_t packetDataSize,void *a4,ENetPeer *peer,int packetFlag)
{
    ENetPacket *p;

    if (peer) // check if we have it setup
    {
        if (a1 == 4 && *(&packetData[12]) & 8)
        {
            p = enet_packet_create(0,packetDataSize + *(&packetData[13]) + 5,packetFlag);
            int four = 4;
            memcpy(p->data,&four,4);
            memcpy((char *)p->data + 4,&packetData[0],packetDataSize);
            void * a4 = 0;
            memcpy((char *)p->data + packetDataSize + 4,a4,*(&packetData[13]));
            enet_peer_send(peer,p);
        }
        else
        {
            p = enet_packet_create(0,packetDataSize + 5,packetFlag);
            memcpy(p->data,&a1,packetDataSize);
            enet_peer_send(peer,p);
        }
    }
    
    packetData.clear();
}
,

我想我在你的代码中看到了一个主要的错误,一个 std::vector<BYTE> data ,在 &data[0] 如果你做地址运算符,你会得到对象地址,因为 [] 是向量类的运算符。所以你可能想使用 data.data() 它会返回一个原始指针,在 memcpy()
之前执行此操作 ps:我的第一个回答

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。