Skip to content

Commit 8664b9a

Browse files
tniessenRafaelGSS
authored andcommitted
src,test: disallow unsafe integer coercion in SQLite
Currently, by default (i.e., when use_big_ints_ has not explicitly been set to true), reading a SQLite integer value that is not a safe integer in JavaScript is likely to yield an incorrect number. Instead, err on the side of caution and throw if the stored integer is not a safe integer in JavaScript and if use_big_ints_ has not been set to true. PR-URL: #53851 Reviewed-By: Colin Ihrig <[email protected]>
1 parent 30a94ca commit 8664b9a

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

src/node_sqlite.cc

+13-4
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,21 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
370370

371371
Local<Value> StatementSync::ColumnToValue(const int column) {
372372
switch (sqlite3_column_type(statement_, column)) {
373-
case SQLITE_INTEGER:
373+
case SQLITE_INTEGER: {
374+
sqlite3_int64 value = sqlite3_column_int64(statement_, column);
374375
if (use_big_ints_) {
375-
return BigInt::New(env()->isolate(),
376-
sqlite3_column_int64(statement_, column));
376+
return BigInt::New(env()->isolate(), value);
377+
} else if (std::abs(value) <= kMaxSafeJsInteger) {
378+
return Number::New(env()->isolate(), value);
379+
} else {
380+
THROW_ERR_OUT_OF_RANGE(env()->isolate(),
381+
"The value of column %d is too large to be "
382+
"represented as a JavaScript number: %" PRId64,
383+
column,
384+
value);
385+
return Local<Value>();
377386
}
378-
// Fall through.
387+
}
379388
case SQLITE_FLOAT:
380389
return Number::New(env()->isolate(),
381390
sqlite3_column_double(statement_, column));

test/parallel/test-sqlite.js

+16
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,22 @@ suite('StatementSync.prototype.setReadBigInts()', () => {
388388
message: /The "readBigInts" argument must be a boolean/,
389389
});
390390
});
391+
392+
test('BigInt is required for reading large integers', (t) => {
393+
const db = new DatabaseSync(nextDb());
394+
const bad = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`);
395+
t.assert.throws(() => {
396+
bad.get();
397+
}, {
398+
code: 'ERR_OUT_OF_RANGE',
399+
message: /^The value of column 0 is too large.*: 9007199254740992$/,
400+
});
401+
const good = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`);
402+
good.setReadBigInts(true);
403+
t.assert.deepStrictEqual(good.get(), {
404+
[`${Number.MAX_SAFE_INTEGER} + 1`]: 2n ** 53n,
405+
});
406+
});
391407
});
392408

393409
suite('StatementSync.prototype.setAllowBareNamedParameters()', () => {

0 commit comments

Comments
 (0)