From 94e72fe471e8308f176f0e02b16a0ae5797bdd9c Mon Sep 17 00:00:00 2001 From: pbbadenhorst <17087278+pbbadenhorst@users.noreply.github.com> Date: Thu, 14 May 2026 15:02:33 -0700 Subject: [PATCH] fix(cpp): out-of-bounds read in delete() when a location is passed --- cpp/DBHostObject.cpp | 6 +++--- example/src/tests/dbsetup.ts | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/cpp/DBHostObject.cpp b/cpp/DBHostObject.cpp index a31c48c5..faf3dde3 100644 --- a/cpp/DBHostObject.cpp +++ b/cpp/DBHostObject.cpp @@ -283,12 +283,12 @@ void DBHostObject::create_jsi_functions(jsi::Runtime &rt) { std::string path = std::string(base_path); if (count == 1) { - if (!args[1].isString()) { + if (!args[0].isString()) { throw std::runtime_error( - "[op-sqlite][open] database location must be a string"); + "[op-sqlite][delete] database location must be a string"); } - std::string location = args[1].asString(rt).utf8(rt); + std::string location = args[0].asString(rt).utf8(rt); if (!location.empty()) { if (location == ":memory:") { diff --git a/example/src/tests/dbsetup.ts b/example/src/tests/dbsetup.ts index 04500a07..60d273f7 100644 --- a/example/src/tests/dbsetup.ts +++ b/example/src/tests/dbsetup.ts @@ -146,6 +146,38 @@ describe("DB setup tests", () => { db.delete(); }); + it("Should delete db when a location argument is passed to delete()", async () => { + const db = open({ + name: "deleteWithLocationArg.sqlite", + encryptionKey: "test", + }); + + // Regression: delete() previously read args[1] when count == 1, which + // read past the JSI argument list and could crash native code. An + // empty-string location exercises the count == 1 / args[0] path; the + // empty-guard in the host function preserves the base path so the file + // is still found and removed. + db.delete(""); + }); + + it("Should reject a non-string location argument to delete()", async () => { + const db = open({ + name: "deleteBadArg.sqlite", + encryptionKey: "test", + }); + + let threw = false; + try { + // @ts-expect-error — intentionally passing a non-string to exercise the guard + db.delete(123); + } catch (e) { + threw = true; + } + expect(threw).toEqual(true); + + db.delete(); + }); + it("Should create db in custom folder", async () => { const db = open({ name: "customFolderTest.sqlite",