Skip to content

Commit c1f5d08

Browse files
committed
[FIXED] EventLoop: Libuv may crash if connection destroyed while consuming
If the user destroys the connection while the read event was in progress it could be possible for the library to crash trying to process a read event. We need to immediately stop polling when the read event is removed. Changing also the way we retain the connection: we will now retain on the very first attach, and the adapters will have to call `natsConnection_Destroy()` when the event loop is fully detached. Resolves #888 Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
1 parent 3682cde commit c1f5d08

File tree

4 files changed

+19
-4
lines changed

4 files changed

+19
-4
lines changed

src/adapters/libevent.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ _freeCb(evutil_socket_t ignoredSocket, short ignoredEvent, void *arg)
240240
event_active(nle->keepActive, 0, 0);
241241
event_free(nle->keepActive);
242242
}
243+
// This will release the connection that is retained by the library on the first attach.
244+
natsConnection_Destroy(nle->nc);
243245
free(nle);
244246
}
245247

src/adapters/libuv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ uvFinalCloseCb(uv_handle_t* handle)
250250
free(nle->scheduler);
251251
uv_mutex_destroy(nle->lock);
252252
free(nle->lock);
253+
// This will release the connection that is retained by the library on the first attach.
254+
natsConnection_Destroy(nle->nc);
253255
free(nle);
254256
}
255257

@@ -421,6 +423,10 @@ natsLibuv_Read(void *userData, bool add)
421423
natsStatus s = NATS_OK;
422424
bool sched;
423425

426+
// If we remove, first stop polling immediately, then proceed as usual.
427+
if (!add)
428+
uv_poll_stop(nle->handle);
429+
424430
sched = ((uv_key_get(&uvLoopThreadKey) != nle->loop) ? true : false);
425431

426432
// If this call is made from a different thread than the event loop's

src/conn.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,18 +2013,28 @@ _processConnInit(natsConnection *nc)
20132013
// event just after this call returns.
20142014
nc->sockCtx.useEventLoop = true;
20152015

2016+
// For the very first attach, we will retain the connection.
2017+
if (!nc->el.retained)
2018+
_retain(nc);
2019+
20162020
s = nc->opts->evCbs.attach(&(nc->el.data),
20172021
nc->opts->evLoop,
20182022
nc,
20192023
(int) nc->sockCtx.fd);
20202024
if (s == NATS_OK)
20212025
{
20222026
nc->el.attached = true;
2027+
nc->el.retained = true;
20232028
}
20242029
else
20252030
{
20262031
nc->sockCtx.useEventLoop = false;
20272032

2033+
// If this was the very first attach and we failed, release the connection
2034+
// to compensate for the retain above.
2035+
if (!nc->el.retained)
2036+
_release(nc);
2037+
20282038
nats_setError(s,
20292039
"Error attaching to the event loop: %d - %s",
20302040
s, natsStatus_GetText(s));
@@ -4164,8 +4174,6 @@ natsConnection_ProcessReadEvent(natsConnection *nc)
41644174
}
41654175
}
41664176

4167-
_retain(nc);
4168-
41694177
buffer = nc->el.buffer;
41704178
size = nc->opts->ioBufSize;
41714179

@@ -4184,8 +4192,6 @@ natsConnection_ProcessReadEvent(natsConnection *nc)
41844192

41854193
if (s != NATS_OK)
41864194
_processOpError(nc, s, false);
4187-
4188-
natsConn_release(nc);
41894195
}
41904196

41914197
void

src/natsp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ struct __natsConnection
771771
{
772772
bool attached;
773773
bool writeAdded;
774+
bool retained; // Will be set to true at the very first successful attach.
774775
void *buffer;
775776
void *data;
776777
} el;

0 commit comments

Comments
 (0)