mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
sqlite: use 64-bit result APIs for UDF return values
JSValueToSQLiteResult() passed the size_t length of returned ArrayBuffers and ArrayBufferViews to sqlite3_result_blob(), which takes an int. Buffers larger than INT_MAX bytes were narrowed, yielding silently truncated blobs or bogus empty text values. Use sqlite3_result_blob64() and sqlite3_result_text64(), matching Statement::BindValue(), so oversized values are rejected with SQLITE_TOOBIG. Assisted-by: Claude Code Signed-off-by: Guilherme Araújo <arauujogui@gmail.com> PR-URL: https://github.com/nodejs/node/pull/67089 Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
1 parent
280798a30d
commit
128f247ea4
2 files changed
+26
-3
No files matched your search
+3
-2
@@ -332,11 +332,12 @@ void JSValueToSQLiteResult(Isolate* isolate,
|
||||
sqlite3_result_double(ctx, value.As<Number>()->Value());
|
||||
} else if (value->IsString()) {
|
||||
Utf8Value val(isolate, value.As<String>());
|
||||
sqlite3_result_text(ctx, *val, val.length(), SQLITE_TRANSIENT);
|
||||
sqlite3_result_text64(
|
||||
ctx, *val, val.length(), SQLITE_TRANSIENT, SQLITE_UTF8);
|
||||
} else if (value->IsArrayBufferView() || value->IsArrayBuffer() ||
|
||||
value->IsSharedArrayBuffer()) {
|
||||
ArrayBufferViewContents<uint8_t> buf(value);
|
||||
sqlite3_result_blob(ctx, buf.data(), buf.length(), SQLITE_TRANSIENT);
|
||||
sqlite3_result_blob64(ctx, buf.data(), buf.length(), SQLITE_TRANSIENT);
|
||||
} else if (value->IsBigInt()) {
|
||||
bool lossless;
|
||||
int64_t as_int = value.As<BigInt>()->Int64Value(&lossless);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
const { skipIfSQLiteMissing, mustCall } = require('../common');
|
||||
const { skipIfSQLiteMissing, mustCall, enoughTestMem } = require('../common');
|
||||
skipIfSQLiteMissing();
|
||||
const assert = require('node:assert');
|
||||
const { Database } = require('node:sqlite');
|
||||
@@ -347,6 +347,28 @@ suite('Database.prototype.function()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('throws if returned buffer exceeds INT_MAX bytes', {
|
||||
skip: !enoughTestMem && 'insufficient memory',
|
||||
}, (t) => {
|
||||
const db = new Database(':memory:');
|
||||
for (const size of [2 ** 31, 2 ** 32 + 5]) {
|
||||
let buf;
|
||||
try {
|
||||
buf = new ArrayBuffer(size);
|
||||
} catch {
|
||||
return t.skip('insufficient memory');
|
||||
}
|
||||
db.function('retLargeBuffer', () => buf);
|
||||
const stmt = db.prepare('SELECT retLargeBuffer() AS retLargeBuffer');
|
||||
assert.throws(() => {
|
||||
stmt.get();
|
||||
}, {
|
||||
code: 'ERR_SQLITE_ERROR',
|
||||
message: /string or blob too big/,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('throws on unsupported return types', () => {
|
||||
const db = new Database(':memory:');
|
||||
db.function('retFunction', () => {
|
||||
|
||||
Reference in new issue
Block a user