better-sqlite3 icon indicating copy to clipboard operation
better-sqlite3 copied to clipboard

db.serialize() crashes in recent Electron versions

Open malshoff opened this issue 8 months ago • 4 comments

The serialize() function doesn't work due to V8 sandboxing?

[23992:0508/184214.301:ERROR:node_bindings.cc(162)] Fatal error in V8: v8_ArrayBuffer_NewBackingStore When the V8 Sandbox is enabled, ArrayBuffer backing stores must be allocated inside the sandbox address space. Please use an appropriate ArrayBuffer::Allocator to allocate these buffers, or disable the sandbox.
 "electron": "^35.3.0",
    "better-sqlite3": "^11.10.0", 

MVR:

private initializeInMemoryDatabase(dbPath: string, isNewGame: boolean = false): void {
    log.info('Initializing database at path: ', dbPath)
    let tempDB: Database = new Database(dbPath)
    const buffer = tempDB.serialize()
    log.info('Database buffer created')
}

I don't want to backup the db, but serialize it and open it as a new db, that I can then write to/read from without writing to the backing file until I choose to. This is for a game, so imagine a video game that has a "save" button, at which point the game saves certain data to the db.

This was working fine on electron 28.2.0, but broke upon updating to the latest version. The DB is not in WAL mode.

For reference, it seems the solution is posted here, but hasn't been merged: https://github.com/WiseLibs/better-sqlite3/pull/1036#issuecomment-2227422329

malshoff avatar May 09 '25 02:05 malshoff

@malshoff have you validated that solution? If so, can you put up a PR?

mceachen avatar May 09 '25 02:05 mceachen

I'm testing it right now, and I'll definitely put up a PR if it works.

malshoff avatar May 09 '25 02:05 malshoff

NICE! Thanks for the effort.

Know that I can’t merge your PR, but I can gently prod those who can.

mceachen avatar May 09 '25 03:05 mceachen

I spent way more time than was probably necessary since I don't really deal much with native node modules and their associated complexities, but I got the fix to work locally. The flag being read was just wrong, as @Prinzhorn speculated. This works properly:

#src
#if defined(V8_ENABLE_SANDBOX)
// When V8 Sandbox is enabled (in newer Electron versions), we need to use Buffer::Copy
// instead of Buffer::New to ensure the ArrayBuffer backing store is allocated inside the sandbox
static inline v8::MaybeLocal<v8::Object> BufferSandboxNew(v8::Isolate* isolate, char* data, size_t length, void (*finalizeCallback)(char*, void*), void* finalizeHint) {
    v8::MaybeLocal<v8::Object> buffer = node::Buffer::Copy(isolate, data, length);
    finalizeCallback(data, finalizeHint);
    return buffer;
}
#define SAFE_NEW_BUFFER(env, data, length, finalizeCallback, finalizeHint) BufferSandboxNew(env, data, length, finalizeCallback, finalizeHint)
#else
// When V8 Sandbox is not enabled, we can use the more efficient Buffer::New
#define SAFE_NEW_BUFFER(env, data, length, finalizeCallback, finalizeHint) node::Buffer::New(env, data, length, finalizeCallback, finalizeHint)
#endif
#end

Tested using

npm run lzz
 npx prebuild -t 35.3.0 -r electron --include-regex 'better_sqlite3.node$'

electron-rebuild only builds from remote apparently, it won't rebuild locally changed packages (from my little experience with it at least), so I used that prebuild command and it properly built the module for electron 35.3.0.

I will check out the contributing guide and make a PR for this, but I wanted to leave this here on the chance that I get busy with something else and don't make a PR soon.

malshoff avatar May 09 '25 19:05 malshoff

This can be closed I assume?

Prinzhorn avatar Jul 03 '25 06:07 Prinzhorn

This can be closed I assume?

Yes

malshoff avatar Jul 03 '25 06:07 malshoff