couchbase / couchbase/couchnode

Possible `FwdFunc` leak when `CallCookie::invoke()` cannot queue the callback

Open
#152 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
462
Forks
225
PR merge metrics
No merged PRs in 30d

Description

Possible FwdFunc leak when CallCookie::invoke() cannot queue the callback

I found a possible native heap leak in CallCookie::invoke() when the thread-safe function is closing.

File: src/connection.hpp

Function: CallCookie::invoke

Relevant code:

void invoke(FwdFunc &&callback)
{
    _ttsf.BlockingCall(new FwdFunc(std::move(callback)));
    _ttsf.Release();
}

The allocated callback is normally released by jscbForward():

void jscbForward(Napi::Env env, Napi::Function callback, std::nullptr_t *,
                 FwdFunc *fn)
{
    if (env == nullptr || callback == nullptr) {
        delete fn;
        return;
    }

    try {
        (*fn)(env, callback);
    } catch (const Napi::Error &e) {
    }
    delete fn;
}

But BlockingCall() returns a napi_status. If it returns a failure such as
napi_closing, the item was not queued and jscbForward() will not run for
that FwdFunc. Since the allocation is created inline in the BlockingCall()
argument, the caller has no remaining pointer to delete on failure.

This helper is used by multiple async completion paths, including
executeOp(), jsConnect(), jsShutdown(), jsOpenBucket(),
jsDiagnostics(), jsPing(), range scans, and transaction callbacks.

Suggested fix: keep ownership until BlockingCall() reports success, and delete
the FwdFunc locally when the call did not queue it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/connection.hpp at CallCookie::invoke and inspect how BlockingCall reports failure while the thread-safe function is closing. Check the listed completion paths, including executeOp(), jsConnect(), and jsShutdown(); done means a failed queue operation retains no allocated FwdFunc and successful callbacks still follow the existing jscbForward() cleanup path.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, node.js
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.