Skip to content

sqlite: memory leak and sqlite API misuse #63831

@ndossche

Description

@ndossche

Version

v24.16.0

Platform

Linux e6fd926f804d 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

sqlite

What steps will reproduce the bug?

Execute the following JS code, with sqlite compiled with SQLITE_ENABLE_API_ARMOR:

const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('/nonexistent-dir/x.db', { open: false, readOnly: true });
try { db.open(); } catch {}  // Can't open, now a "sick" handle
console.log(db.isOpen);      // true
db.function('f', () => {});  // create_function_v2 -> SQLITE_MISUSE_BKPT, `UserDefinedFunction* user_data` leaked

This will trigger a leak via sqlite's API abuse detector. See below for the ASAN output.

How often does it reproduce? Is there a required condition?

Always if compiled with SQLITE_ENABLE_API_ARMOR

What is the expected behavior? Why is that the expected behavior?

No leak. In fact, it should not be possible to get into this situation in the first place: the API misuse guard of the sqlite API should never trigger. Node.js should block getting into this situation.

What do you see instead?

=================================================================
==370239==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x6391a602b411 in operator new(unsigned long) (/work/node/out/Debug/node+0xae2b411) (BuildId: af8ea042dbd52fe317d72d87d06d3dbfb9aa7fa9)
    #1 0x6391a71cdaa7 in node::sqlite::DatabaseSync::CustomFunction(v8::FunctionCallbackInfo<v8::Value> const&) /work/node/out/../src/node_sqlite.cc:1401:7
    #2 0x714010e12f8c in Builtins_CallApiCallbackGeneric embedded.o
    #3 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #4 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #5 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #6 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #7 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #8 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #9 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #10 0x714010e11512 in Builtins_InterpreterEntryTrampoline embedded.o
    #11 0x714010e0df26 in Builtins_JSEntryTrampoline embedded.o
    #12 0x714010e0dc66 in Builtins_JSEntry embedded.o
    #13 0x6391a7e71586 in v8::internal::GeneratedCode<unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, long, unsigned long**>::Call(unsigned long, unsigned long, unsigned long, unsigned long, long, unsigned long**) /work/node/out/../deps/v8/src/execution/simulator.h:212:12
    #14 0x6391a7e71586 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) /work/node/out/../deps/v8/src/execution/execution.cc:442:22
    #15 0x6391a7e6e194 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>) /work/node/out/../deps/v8/src/execution/execution.cc:532:10
    #16 0x531000015287  (<unknown module>)

SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s).

Additional information

Found with an experimental static-dynamic hybrid analyzer I'm developing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions