diff --git a/native.js b/native.js index 7cee9553fd..c5be4e42fe 100644 --- a/native.js +++ b/native.js @@ -2,7 +2,7 @@ import { dirname, default as pathModule } from 'path'; import { fileURLToPath } from 'url'; import { createRequire } from 'module'; -export let Env, Txn, Dbi, Compression, Cursor, getAddress, clearKeptObjects, setGlobalBuffer, +export let Env, Txn, Dbi, Compression, Cursor, getAddress, createBufferForAddress, clearKeptObjects, setGlobalBuffer, require, arch, fs, os, onExit, tmpdir, lmdbError, path, EventEmitter, orderedBinary, MsgpackrEncoder, WeakLRUCache, setEnvMap, getEnvMap, getByBinary, detachBuffer, write, position, iterate, native, v8AccelerationEnabled = false; require = createRequire(import.meta.url); @@ -36,6 +36,7 @@ export function setNativeFunctions(externals) { Dbi = externals.Dbi; Compression = externals.Compression; getAddress = externals.getAddress; + createBufferForAddress = externals.createBufferForAddress; clearKeptObjects = externals.clearKeptObjects || function() {}; Cursor = externals.Cursor; lmdbError = externals.lmdbError; diff --git a/src/lmdb-js.h b/src/lmdb-js.h index 999bc79b93..d806fa3281 100644 --- a/src/lmdb-js.h +++ b/src/lmdb-js.h @@ -141,7 +141,7 @@ bool getVersionAndUncompress(MDB_val &data, DbiWrap* dw); int compareFast(const MDB_val *a, const MDB_val *b); Value setGlobalBuffer(const CallbackInfo& info); Value lmdbError(const CallbackInfo& info); -//NAN_METHOD(getBufferForAddress); +napi_value createBufferForAddress(napi_env env, napi_callback_info info); napi_value getViewAddress(napi_env env, napi_callback_info info); napi_value detachBuffer(napi_env env, napi_callback_info info); Value getAddress(const CallbackInfo& info); diff --git a/src/misc.cpp b/src/misc.cpp index 3bf97d630c..ebd62177d6 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -24,8 +24,8 @@ void setupExportMisc(Napi::Env env, Object exports) { exports.Set("version", versionObj); exports.Set("setGlobalBuffer", Function::New(env, setGlobalBuffer)); exports.Set("lmdbError", Function::New(env, lmdbError)); - //exports.Set("getBufferForAddress", Function::New(env, getBufferForAddress)); exports.Set("enableDirectV8", Function::New(env, enableDirectV8)); + EXPORT_NAPI_FUNCTION("createBufferForAddress", createBufferForAddress); EXPORT_NAPI_FUNCTION("getAddress", getViewAddress); EXPORT_NAPI_FUNCTION("detachBuffer", detachBuffer); } @@ -134,6 +134,16 @@ Value setGlobalBuffer(const CallbackInfo& info) { auto array_buffer = v8::ArrayBuffer::New(Isolate::GetCurrent(), std::move(backing)); info.GetReturnValue().Set(array_buffer); }*/ +NAPI_FUNCTION(createBufferForAddress) { + ARGS(2) + void* data; + GET_INT64_ARG(data, 0); + size_t length; + GET_INT64_ARG(length, 1); + napi_create_external_buffer(env, length, data, nullptr, nullptr, &returnValue); + return returnValue; +} + NAPI_FUNCTION(getViewAddress) { ARGS(1) void* data; diff --git a/test/index.test.js b/test/index.test.js index f80c58a216..d70c6555fb 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -13,6 +13,7 @@ import inspector from 'inspector' let nativeMethods, dirName = dirname(fileURLToPath(import.meta.url)) import { open, levelup, bufferToKeyValue, keyValueToBuffer, asBinary, ABORT, IF_EXISTS } from '../index.js'; +import { createBufferForAddress } from '../native.js' import { RangeIterable } from '../util/RangeIterable.js' import { assert } from 'console'; import { openAsClass } from '../open.js'; @@ -97,6 +98,8 @@ describe('lmdb-js', function() { it('zero length values', async function() { await db.committed // should be able to await db even if nothing has happened db.put(5, asBinary(Buffer.from([]))); + db.put(5, asBinary(createBufferForAddress(16, 0)));// externally allocated buffers of zero-length with the same non-null-pointer can crash node, #161 + db.put(5, asBinary(createBufferForAddress(16, 0))); await db2.put('key1', asBinary(Buffer.from([]))); should.equal(db.getBinary(5).length, 0); should.equal(db2.getBinary('key1').length, 0); diff --git a/write.js b/write.js index d92f03ef7c..76f1dfe2c3 100644 --- a/write.js +++ b/write.js @@ -175,7 +175,8 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use let valueArrayBuffer = valueBuffer.buffer; // record pointer to value buffer float64[position] = (valueArrayBuffer.address || - (valueArrayBuffer.address = (getAddress(valueBuffer) - valueBuffer.byteOffset))) + (valueBuffer.length === 0 ? 0 : // externally allocated buffers of zero-length with the same non-null-pointer can crash node, #161 + (valueArrayBuffer.address = (getAddress(valueBuffer) - valueBuffer.byteOffset)))) + valueBuffer.byteOffset; mustCompress = valueBuffer[0] >= 250; // this is the compression indicator, so we must compress }