nats-io / nats.c

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

segfault when calling js_Subscribe for an ephemeral subscription #695

Open jtrberg opened 11 months ago

jtrberg commented 11 months ago

Observed behavior

The following code occasionally causes a segfault when performing an ephemeral subscription to a subject in a WorkQueue stream.

js_Subscribe(&mSubscription, mJs, mSubjectName.c_str()/*subject*/, &onMsg, this/*closure*/, mJsOpts, mJsSubOpts, &jsErr)

The issue appears to be that the _subscribe proc it calls:

static natsStatus
_subscribe(natsSubscription **new_sub, jsCtx *js, const char *subject, const char *pullDurable,
           natsMsgHandler usrCB, void *usrCBClosure, bool isPullMode,
           jsOptions *jsOpts, jsSubOptions *opts, jsErrCode *errCode)
{
...
    if ((s == NATS_OK) && create)
    {
        // Multiple subscribers could compete in creating the first consumer
        // that will be shared using the same durable name. If this happens, then
        // do a lookup of the consumer info subscribe using the latest info.
        s = js_AddConsumer(&info, js, stream, cfg, &jo, &jerr);
        if (s != NATS_OK)
        {
...
        }
        else
        {
            maxap = info->Config->MaxAckPending;
            natsSub_Lock(sub);
            jsi->dc = true;
            jsi->pending = info->NumPending + info->Delivered.Consumer;
            // There may be a race in the case of an ordered consumer where by this
            // time, the consumer has been recreated (jsResetOrderedConsumer). So
            // set only if jsi->consumer is NULL!
            if (jsi->consumer == NULL)
            {
                DUP_STRING(s, jsi->consumer, info->Name);  // <------ SEGFAULT HERE because info->Name == 0x0
                if (s == NATS_OK)
                {
                    NATS_FREE(jsi->nxtMsgSubj);
                    jsi->nxtMsgSubj = NULL;
                    if (nats_asprintf(&(jsi->nxtMsgSubj), jsApiRequestNextT, jo.Prefix, stream, jsi->consumer) < 0)
                        s = nats_setDefaultError(NATS_NO_MEMORY);
                }
            }
            natsSub_Unlock(sub);
        }
    }

END:
...

    return NATS_UPDATE_ERR_STACK(s);
}

Expected behavior

Subscribe should succeed and create the ephemeral consumer.

Server and client version

server version is: 2.10.4 client version is: 3.7.0

Host environment

linux

Steps to reproduce

Does not repro all the time, seems to only occur under load.