nats-io / nats.c

A C client for NATS
Apache License 2.0
390 stars 137 forks source link

natsConnection_Connect can get stuck in a very long, unproductive loop #706

Closed jtrberg closed 9 months ago

jtrberg commented 9 months ago

Observed behavior

natsConnection_Connect can get stuck in a very long, unproductive loop when natsSock_Read called inside _readProto returns: NATS_IO_ERROR

>   natsd.dll!_readProto(__natsConnection * nc, __natsBuffer * * proto) Line 1798   C
    natsd.dll!_sendConnect(__natsConnection * nc) Line 1857 C
    natsd.dll!_processConnInit(__natsConnection * nc) Line 1937 C
    natsd.dll!_connect(__natsConnection * nc) Line 2024 C
    natsd.dll!natsConnection_Connect(__natsConnection * * newConn, __natsOptions * options) Line 3284   C

This code will get stuck rapidly iterating and trying to append a \0 byte into the receive buffer (expanding the buffer over and over until it runs out of memory. In my testing the buffer capacity grew to 61588108 out of max 65851395 when I was waiting for a while, obviously this loop spins millions of times.

See code implementation below, only if the returned error is: NATS_CONNECTION_CLOSED would the loop exit immediately.

// reads a protocol one byte at a time.
static natsStatus
_readProto(natsConnection *nc, natsBuffer **proto)
{
    natsStatus  s           = NATS_OK;
    char        protoEnd    = '\n';
    natsBuffer  *buf        = NULL;
    char        oneChar[1]  = { '\0' };

    s = natsBuf_Create(&buf, 10);
    if (s != NATS_OK)
        return s;

    for (;;)
    {
        s = natsSock_Read(&(nc->sockCtx), oneChar, 1, NULL);
        if (s == NATS_CONNECTION_CLOSED)
            break;
        s = natsBuf_AppendByte(buf, oneChar[0]);
        if (s != NATS_OK)
        {
            natsBuf_Destroy(buf);
            return s;
        }
        if (oneChar[0] == protoEnd)
            break;
    }
    s = natsBuf_AppendByte(buf, '\0');
    if (s != NATS_OK)
    {
        natsBuf_Destroy(buf);
        return s;
    }
    *proto = buf;
    return NATS_OK;
}

Expected behavior

Expect connect call to fail out quickly.

Server and client version

Server: v2.10.7 Nats.C: 3.7.0

Host environment

Windows

Steps to reproduce

Any situation that would result in: NATS_IO_ERROR when trying to connect to the server should reproduce this issue.

kozlovic commented 9 months ago

@jtrberg Will get this fixed. Thank you for the report!