[CONC-364] Not all sockets created in pvio_socket_connect function are closed Created: 2018-09-25  Updated: 2018-10-23  Resolved: 2018-10-23

Status: Closed
Project: MariaDB Connector/C
Component/s: None
Affects Version/s: 3.0.6
Fix Version/s: 3.0.7, 3.1.0

Type: Bug Priority: Major
Reporter: Sergey Pashkov Assignee: Georg Richter
Resolution: Fixed Votes: 1
Labels: None
Environment:

macOS 10.13.4



 Description   

The problem is reproducible if you try to connect to the inactive server on localhost(or 127.0.0.1).

Open pvio_socket.c. The following call of getaddrinfo returns linked list of two items: IPv6 and IPv4 addresses

 /* Get the address information for the server using getaddrinfo() */
    wait_gai= 1;
    while ((gai_rc= getaddrinfo(cinfo->host, server_port,
                                &hints, &res)) == EAI_AGAIN)
    {

Then a new socket is created for each item in the list:

for (save_res= res; save_res; save_res= save_res->ai_next)
    {
      csock->socket= socket(save_res->ai_family, save_res->ai_socktype, 
                            save_res->ai_protocol);

And attempt to connect:

rc= pvio_socket_connect_sync_or_async(pvio, save_res->ai_addr, (uint)save_res->ai_addrlen);

But when the error handling is made, only the last created socket is closed:

/* close socket: MDEV-10891 */
  if (csock->socket != INVALID_SOCKET)
  {
    closesocket(csock->socket);
    csock->socket= INVALID_SOCKET;
  }

While the previous (IPv6 in that case) remains not freed, which can be easily checked with lsof:

$ lsof -p 95552 | grep CLOSED
ClientApp 95552 sergey 18u IPv6 0x9bc9e6ea54fa1537 0t0 TCP localhost:64829->localhost:mysql (CLOSED)

If multiple attempts are made the resource limit will be exceeded.



 Comments   
Comment by Gus Ito [ 2018-10-19 ]

In case it helps, here you are the fix I've applied on my build:

/plugins/pvio/pvio_socket.c

    /* res is a linked list of addresses for the given hostname. We loop until
       we are able to connect to one address or all connect attempts failed */
    for (save_res= res; save_res; save_res= save_res->ai_next)
    {
		if(csock->socket != INVALID_SOCKET) /*avoid socket leak CONC-364 */
			closesocket(csock->socket);
		csock->socket= socket(save_res->ai_family, save_res->ai_socktype, 
                            save_res->ai_protocol);
      if (csock->socket == INVALID_SOCKET)
        /* Errors will be handled after loop finished */
        continue;

Generated at Thu Feb 08 03:04:47 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.