c++socketsmemory-managementmemory-leaksmemory-leak-detector

Memory leak on socket


I'm writing a tcp proxy and while it seem to work it leaves a memory leak behind. I manipulated the code to forward the incoming packet to itself to create 10000 sockets and close them to see where the leak is. However I can't figure it out. I've used deleaker and it doesn't shows any leak(besides a small one that I don't care.) http://i.imgur.com/7r6u4Jd.png

But then I untick the two boxes and this comes out. enter image description here

Any help would be appreciated!

Code:

#include <winsock2.h>
#include <stdio.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <tchar.h>
#include <process.h> /* _beginthread() */

// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define PORT    "1234" /* Port to listen on */
#define BUF_SIZE 4096    /* Buffer for  transfers */

typedef struct {

    char *host;
    char *port;
    SOCKET sock;

}
HandleStruct;

unsigned int S2C(SOCKET from, SOCKET to)
{

    char buf[BUF_SIZE];
    unsigned int disconnected = 0;
    size_t bytes_read, bytes_written;
    bytes_read = recv(from, buf, BUF_SIZE, 0);
    if (bytes_read == 0) {

        disconnected = 1;

    }

    else {

        bytes_written = send(to, buf, bytes_read, 0);
        if (bytes_written == -1) {

            disconnected = 1;

        }


    }

    return disconnected;

}

unsigned int C2S(SOCKET from, SOCKET to)
{

    char buf[BUF_SIZE];
    unsigned int disconnected = 0;
    size_t bytes_read, bytes_written;
    bytes_read = recv(from, buf, BUF_SIZE, 0);
    if (bytes_read == 0) {

        disconnected = 1;

    }

    else {

        bytes_written = send(to, buf, bytes_read, 0);
        if (bytes_written == -1) {

            disconnected = 1;

        }


    }

    return disconnected;

}

void handle(void *param)
{

    HandleStruct *args = (HandleStruct*) param;
    SOCKET client = args->sock;
    const char *host = args->host;
    const char *port = args->port;
    SOCKET server = -1;
    unsigned int disconnected = 0;
    fd_set set;
    unsigned int max_sock;
    struct addrinfo *res = NULL;
    struct addrinfo *ptr = NULL;
    struct addrinfo hints;
    /* Get the address info */
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    if (getaddrinfo(host, port, &hints, &res) != 0) {

        perror("getaddrinfo");
        closesocket(client);
        return;

    }

    /* Create the socket */
    server = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (server == INVALID_SOCKET) {

        perror("socket");
        closesocket(client);
        return;

    }

    /* Connect to the host */
    if (connect(server, res->ai_addr, res->ai_addrlen) == -1) {

        perror("connect");
        closesocket(client);
        return;

    }

    if (client > server) {

        max_sock = client;

    }

    else {

        max_sock = server;

    }

    /* Main transfer loop */
    while (!disconnected) {

        FD_ZERO(&set);
        FD_SET(client, &set);
        FD_SET(server, &set);
        if (select(max_sock + 1, &set, NULL, NULL, NULL) == SOCKET_ERROR) {

            perror("select");
            break;

        }

        if (FD_ISSET(client, &set)) {

            disconnected = C2S(client, server);

        }

        if (FD_ISSET(server, &set)) {

            disconnected = S2C(server, client);

        }


    }

    closesocket(server);
    closesocket(client);
fprintf(stderr, "Sockets Closed: %d/%d", server, client);
    _endthread();
    return;

}

int _tmain(int argc)
{

    WORD wVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    int iResult;
    SOCKET sock;
    struct addrinfo hints, *res;
    int reuseaddr = 1; /* True */
    /* Initialise Winsock */
    if (iResult = (WSAStartup(wVersion, &wsaData)) != 0) {

        fprintf(stderr, "WSAStartup failed: %dn", iResult);
        return 1;

    }

    char * host = "127.0.0.1";
    char * port = "1234";

    /* Get the address info */
    ZeroMemory(&hints, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    if (getaddrinfo(NULL, PORT, &hints, &res) != 0) {

        perror("getaddrinfo");
        WSACleanup();
        return 1;

    }

    /* Create the socket */
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == INVALID_SOCKET) {

        perror("socket");
        WSACleanup();
        return 1;

    }

    /* Enable the socket to reuse the address */
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr,
    sizeof(int)) == SOCKET_ERROR) {

        perror("setsockopt");
        WSACleanup();
        return 1;

    }

    /* Bind to the address */
    if (bind(sock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR) {

        perror("bind");
        WSACleanup();
        return 1;

    }

    /* Listen */
    if (listen(sock, 6500) == SOCKET_ERROR) {

        perror("listen");
        WSACleanup();
        return 1;

    }

    freeaddrinfo(res);
    int i = 0;

    HandleStruct *arg;
    arg = (HandleStruct *)malloc(sizeof( HandleStruct));
/* Main loop */
    while(1) {

        int size = sizeof(struct sockaddr);
        struct sockaddr_in their_addr;
        SOCKET newsock;
        ZeroMemory(&their_addr, sizeof (struct sockaddr));
        newsock = accept(sock, (struct sockaddr*)&their_addr, &size);

        if (newsock == INVALID_SOCKET) {

            perror("acceptn");

        }
        else {

            arg->sock = newsock;
            arg->host = host;
            arg->port = port;

            if (i < 10000) {
                _beginthread(handle, 0, (void*) arg);
                i++;
            }
        }
    }

    closesocket(sock);
    WSACleanup();
    return 0;

}

Solution

  • I'm not familiar with reading the program in the screenshots you posted; however, you should probably be concerned about this line:

    arg = (HandleStruct *)malloc(sizeof( HandleStruct));
    

    Here you are allocating memory for a HandleStruct via malloc() which doesn't appear to be cleaned up anywhere with a subsequent call to free(). You pass arg into handle() but still don't deallocate the memory.

    It doesn't appear to be handle()'s responsibility to clean arg up, so you should probably have a call to free() after the while loop, or you could allocate the HandleStruct at the beginning of each loop and deallocate it at the end.

    Or you could save yourself the hassle and use std::unique_ptr, and optionally change your threads to std::thread, which self-documents who owns the memory etc:

    void handle(std::unique_ptr<HandleStruct> args)
    {
        // Manipulate args
        ...
    }
    
    int main()
    {
        std::unique_ptr<HandleStruct> pHandle = std::make_unique<HandleStruct>();
        for (;;)
        {
            ...
            pHandle->sock = newsock;
            pHandle->host = host;
            pHandle->port = port;
            // Create thread:
            std::thread t(&handle, pHandle);
            // Wait for thread to finish so pHandle doesn't change while we are using it on another thread
            // t.join();
        }
    }