Skip to content

sharp + sqlite3 Segfault on ARM64 Linux #1851

@jagould2012

Description

@jagould2012

Issue Summary

When using both sharp and sqlite3 native modules together on ARM64 Linux, loading sqlite3 before sharp causes a segmentation fault when subsequently executing SQLite queries. Loading sharp first prevents the crash.

Steps to Reproduce

Environment

  • OS: Kali Linux (Raspberry Pi 5)
  • Architecture: ARM64 (aarch64)
  • Kernel: 6.12.34+rpt-rpi-2712
  • Page Size: 16KB (getconf PAGE_SIZE returns 16384)
  • Node.js: v22.21.1
  • sharp: 0.34.5
  • sqlite3: 5.1.7

Description

There appears to be a conflict between the native bindings of sharp (which uses libvips) and sqlite3 on ARM64 Linux systems. When sqlite3 is initialized first and queries are executed successfully, subsequently loading sharp corrupts some internal state. Any SQLite query executed after sharp is loaded results in a segmentation fault.

The issue does not occur when sharp is loaded before sqlite3 is initialized.

Steps to Reproduce

  1. Set up an ARM64 Linux system (tested on Raspberry Pi 5 with Kali Linux)
  2. Install Node.js v22.x
  3. Create a test project and install both modules:
mkdir sharp-sqlite-test
cd sharp-sqlite-test
npm init -y
npm install sharp sqlite3
  1. Run the bug demonstration script (see below)

Minimal Reproduction - Bug Demonstration

Save as bug-demo.js:

#!/usr/bin/env node
/**
 * Demonstrates sharp + sqlite3 segfault on ARM64 Linux
 * 
 * This script will crash with a segmentation fault on affected systems.
 * The crash occurs because sqlite3 is loaded before sharp.
 */

const sqlite3 = require('sqlite3').verbose();

console.log('Node:', process.version);
console.log('Arch:', process.arch);
console.log('Platform:', process.platform);
console.log('');

// Create an in-memory database
const db = new sqlite3.Database(':memory:');

console.log('[1] sqlite3 loaded and database created');

// Execute a query - this works fine
db.get('SELECT 1 as test', [], (err, row) => {
    if (err) {
        console.error('Query error:', err);
        process.exit(1);
    }
    console.log('[2] First query OK:', row);
    
    // Now load sharp AFTER sqlite3 is already initialized
    console.log('[3] Loading sharp...');
    const sharp = require('sharp');
    console.log('[4] sharp loaded');
    
    // This query will cause a segmentation fault
    console.log('[5] Executing second query (will crash)...');
    db.get('SELECT 2 as test', [], (err, row) => {
        // This callback is never reached
        console.log('[6] Second query OK:', row);
        console.log('SUCCESS - No crash!');
        process.exit(0);
    });
});

Run with:

node bug-demo.js

Expected output on affected systems:

Node: v22.21.1
Arch: arm64
Platform: linux

[1] sqlite3 loaded and database created
[2] First query OK: { test: 1 }
[3] Loading sharp...
[4] sharp loaded
[5] Executing second query (will crash)...
zsh: segmentation fault  node bug-demo.js

Workaround - Loading sharp First

Save as fix-demo.js:

#!/usr/bin/env node
/**
 * Demonstrates the fix: load sharp BEFORE sqlite3
 * 
 * By loading sharp first, the segfault is avoided.
 */

// WORKAROUND: Load sharp BEFORE sqlite3
console.log('[1] Loading sharp FIRST...');
const sharp = require('sharp');
console.log('[2] sharp loaded');

const sqlite3 = require('sqlite3').verbose();

console.log('Node:', process.version);
console.log('Arch:', process.arch);
console.log('Platform:', process.platform);
console.log('');

// Create an in-memory database
const db = new sqlite3.Database(':memory:');

console.log('[3] sqlite3 loaded and database created');

// Execute a query - this works fine
db.get('SELECT 1 as test', [], (err, row) => {
    if (err) {
        console.error('Query error:', err);
        process.exit(1);
    }
    console.log('[4] First query OK:', row);
    
    // Execute another query - this also works now
    console.log('[5] Executing second query...');
    db.get('SELECT 2 as test', [], (err, row) => {
        if (err) {
            console.error('Query error:', err);
            process.exit(1);
        }
        console.log('[6] Second query OK:', row);
        console.log('');
        console.log('SUCCESS - No crash when sharp is loaded first!');
        process.exit(0);
    });
});

Run with:

node fix-demo.js

Expected output:

[1] Loading sharp FIRST...
[2] sharp loaded
Node: v22.21.1
Arch: arm64
Platform: linux

[3] sqlite3 loaded and database created
[4] First query OK: { test: 1 }
[5] Executing second query...
[6] Second query OK: { test: 2 }

SUCCESS - No crash when sharp is loaded first!

Analysis

The issue appears to be related to how the native bindings of these two modules interact on ARM64 Linux:

  1. Memory allocator conflict: Both libvips (used by sharp) and SQLite have their own memory management. Loading them in a specific order may cause conflicts.

  2. Thread pool interference: Both modules use thread pools for async operations. Sharp's initialization may interfere with SQLite's thread pool.

  3. 16KB page size: This system uses 16KB pages instead of the typical 4KB. This may exacerbate memory alignment or mapping issues between native modules.

Affected Software

This bug was discovered while running [ENiGMA½ BBS](https://github.com/NuSkooler/enigma-bbs) on a Raspberry Pi 5 with Kali Linux. The BBS uses both sharp (via avatar-generator) and sqlite3 for its database.

Workaround

Add require('sharp') at the very top of your application's entry point, before any other modules that might load sqlite3:

#!/usr/bin/env node

// WORKAROUND: Must load sharp before sqlite3 to avoid ARM64 segfault
require('sharp');

// ... rest of your application

Additional Information

  • Rebuilding sqlite3 from source (npm install sqlite3 --build-from-source) does not fix the issue
  • Rebuilding sharp from source does not fix the issue
  • The issue is timing-independent (adding delays doesn't help)
  • The issue only manifests on ARM64; x86_64 systems are not affected
  • Running an intermediate SQLite query between loading sqlite3 and sharp can sometimes prevent the crash, suggesting the corruption occurs during sharp's initialization

Version

5.1.7

Node.js Version

22.21.1

How did you install the library?

Kali Linux (Raspberry Pi 5) ARM64 (aarch64)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions