zpl-c / enet

⚡️ ENet reliable UDP networking library
https://blog.zpl.pw
MIT License
699 stars 60 forks source link

malloc(): unaligned tcache chunk detected When trying to send data back from server #27

Closed localcc closed 3 years ago

localcc commented 3 years ago

What should happen: library should continue working and sending packets back and forth What happens: library crashes application with malloc(): unaligned tcache chunk detected

Code to reproduce: Server

#include <iostream>
#define ENET_IMPLEMENTATION
#define ENET_DEBUG
#include <enet.h>

int main()
{
    ENetAddress address{};
    address.host = ENET_HOST_ANY;
    address.port = 3000;

    ENetHost* host = enet_host_create(&address, 32, 2, 0, 0);
    if(host == nullptr) {
        return -1;
    }

    ENetEvent event;
    int res = enet_host_service(host, &event, 0);
    while(res >= 0 && true) {
        switch(event.type) {
            case ENET_EVENT_TYPE_CONNECT:
                std::cout << "Connected!" << std::endl;
            break;
        case ENET_EVENT_TYPE_RECEIVE: {
            std::cout << "Received packet!" << std::endl;

            auto* data = new uint8_t[16];
            ENetPacket* packet = enet_packet_create(data, 16, 0);
            enet_peer_send(event.peer, 1, packet);
            enet_packet_destroy(packet);
            delete[] data;
            enet_host_flush(host);

            enet_packet_destroy(event.packet);
            break;
        }
        case ENET_EVENT_TYPE_DISCONNECT:
            std::cout << "Disconnect" << std::endl;
            break;
        case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
            std::cout << "Disconnect timeout" << std::endl;
            break;
        case ENET_EVENT_TYPE_NONE:
            break;
        }
        res = enet_host_service(host, &event, 0);

    }
}

Client

#include <iostream>
#define ENET_IMPLEMENTATION
#define ENET_DEBUG
#include <enet.h>
#include <thread>

int main()
{
    ENetAddress address{};
    enet_address_set_host(&address, "127.0.0.1");
    address.port = 3000;

    ENetHost* host = enet_host_create(nullptr, 1, 2, 0, 0);
    if(host == nullptr) {
        return -1;
    }

    ENetPeer* peer = enet_host_connect(host, &address, 2, 0);
    if(peer == nullptr) {
        return -2;
    }

    bool connected = false;
    ENetEvent event;
    while(enet_host_service(host, &event, 0) >= 0) {
        switch(event.type) {
        case ENET_EVENT_TYPE_CONNECT:
            std::cout << "Connected!" << std::endl;
            connected = true;
            break;
        case ENET_EVENT_TYPE_RECEIVE:
            std::cout << "Received packet!" << std::endl;
            enet_packet_destroy(event.packet);
            break;
        case ENET_EVENT_TYPE_DISCONNECT:
            std::cout << "Disconnect!" << std::endl;
            break;
        case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT:
            std::cout << "Disconnect timeout!" << std::endl;
            break;
        case ENET_EVENT_TYPE_NONE:
            break;
        }
        if(connected) {
            for(int i = 0; i < 100; i++) {
                auto* data = new uint8_t[16];
                ENetPacket* packet = enet_packet_create(data, 16, 0);
                enet_peer_send(peer, 0, packet);
                delete[] data;
                enet_packet_destroy(packet);
            }
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }

    return 0;
}
inlife commented 3 years ago

Hello,

Please try not to destroy the packet after you enqueued it for sending. If I remember correctly unless you define a flag for manual memory management for the packet, the destruction should happen automatically after the packet was successfully sent (please keep in mind there might be some re-sends happening). You can check the source code for more details.

Cheers!

localcc commented 3 years ago

Thanks, that worked. By the way, there is another issue when server gets flooded with packets enet_host_service returns -1 and errno is set to EAGAIN, shouldn't the library handle that case and continue working?

inlife commented 3 years ago

Not exactly sure about your use case. Have you tried researching this issue within the original fork? It has a much bigger knowledgebase stored within the issue section.

localcc commented 3 years ago

Haven't found any issues in original fork. But based on original fork's code this should occur there too, it will happen on my previous sample code if removing std::this_thread::sleep_for. The library will print Error receiving incoming packets: Resource temporarily unavailable Linux socket wiki says that means packets should be queried again, and that is being confirmed by errno flag being set to EAGAIN

localcc commented 3 years ago

After some information scattering found that this actually should happen because that is how nonblocking sockets work in linux network stack. Anyways as the issue was solved, closing it. Thanks!