Skip to content

Support alternative SQLite backends (node:sqlite) to avoid native addon SIGSEGV crashes #228

@Alexey-Goru1ev

Description

@Alexey-Goru1ev

Problem

context-mode crashes intermittently with SIGSEGV (Signal 11) when running on Node.js v22/v24 on Linux due to a V8 runtime bug that corrupts better-sqlite3's native addon .got.plt section.

Root cause

V8's garbage collector calls madvise(MADV_DONTNEED) on memory ranges that can overlap better_sqlite3.node's writable ELF segments (.got.plt). This discards resolved symbol addresses on Copy-on-Write pages, restoring unrelocated on-disk offsets — causing function calls to jump to near-null addresses.

Upstream issue: nodejs/node#62515"Sporadic SIGSEGV: native addon .got.plt reset to unrelocated file offsets"

Why context-mode is especially affected

  • Runs as an MCP server over stdio pipes (the documented trigger condition)
  • Makes frequent better-sqlite3 calls for FTS5 indexing and search
  • High call frequency under sustained I/O maximizes exposure to the race condition

Crash frequency

Node Version Crash Frequency Tested On
v24.14.x ~4 crashes/hour Ubuntu 24.04, Linux 6.19.10, AMD x86-64
v22.22.x ~1 crash/2 hours Same environment

All coredumps show the same pattern: frame #0 at near-null address (0x12xxx range), consistent with .got.plt corruption.

What doesn't help

Attempted Fix Result
Downgrade Node v24 → v22 Reduced frequency ~10x, did not eliminate
Upgrade better-sqlite3 to v12.8.0 (V8 HolderV2 fix) No effect — crash persists
LD_BIND_NOW=1 (eager symbol resolution) Partial — changes memory layout only
LD_PRELOAD madvise guard (intercept+block on .node segments) Effective but fragile — requires compiled C library, supervisor wrapper, auto-heal hook

The only reliable fix is eliminating the separate .node binary that gets dlopen()'d as a standalone ELF file.

Proposal: Support pluggable SQLite backends

The codebase already has the right abstraction for this:

  1. BunSQLiteAdapter (db-base.ts:40-104) already bridges bun:sqlite → better-sqlite3 API
  2. loadDatabase() (db-base.ts:117-138) already has runtime detection (Bun vs Node)
  3. SQLiteBase provides a clean abstract base that doesn't depend on better-sqlite3 directly
  4. better-sqlite3 is already declared as an optionalDependency, not a hard requirement

Suggested approach

Add a node:sqlite adapter (similar to BunSQLiteAdapter) for Node.js >= 22.5:

loadDatabase() priority:
  1. Bun runtime    → bun:sqlite    (existing BunSQLiteAdapter)
  2. Node >= 22.5   → node:sqlite   (new NodeSQLiteAdapter)  ← NEW
  3. Node < 22.5    → better-sqlite3 (existing, fallback)

node:sqlite is built into the Node.js binary — no separate .node file, no dlopen(), no .got.plt to corrupt. It supports the same synchronous API pattern that context-mode uses.

Alternatively: user-configurable backend

Allow users to specify their preferred backend via environment variable or plugin config:

CONTEXT_MODE_SQLITE_BACKEND=node   # use node:sqlite
CONTEXT_MODE_SQLITE_BACKEND=bun    # use bun:sqlite
CONTEXT_MODE_SQLITE_BACKEND=native # use better-sqlite3 (default)

API compatibility notes

The following better-sqlite3 APIs are used by context-mode and would need adapter coverage:

API Used For node:sqlite equivalent
prepare(sql) Statement caching db.prepare(sql)
stmt.run/get/all() CRUD operations Same API names
exec(sql) Schema DDL db.exec(sql)
pragma(str) WAL, checkpoints db.exec('PRAGMA ...')
transaction(fn) Atomic writes Manual BEGIN/COMMIT wrapper
FTS5 MATCH, bm25(), highlight() Full-text search Same (SQLite feature, not library feature)

FTS5 is a SQLite extension, not a better-sqlite3 feature — it works with any SQLite binding that ships a complete SQLite build.

Environment

  • OS: Ubuntu 24.04, Linux 6.19.10
  • Arch: AMD x86-64
  • Node: v22.22.2 / v24.14.1 (via nvm)
  • context-mode: v1.0.74
  • better-sqlite3: v12.8.0
  • RAM: 13 GiB (4 GB swap used — increases V8 GC pressure → more madvise collisions)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions