Skip to content

Commit b3212b4

Browse files
authored
fix(NODE-6764): incorrect negative bigint handling (#752)
1 parent 011e85e commit b3212b4

File tree

3 files changed

+58
-9
lines changed

3 files changed

+58
-9
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
"build:bundle": "rollup -c rollup.config.mjs",
112112
"build": "npm run build:dts && npm run build:bundle",
113113
"check:lint": "ESLINT_USE_FLAT_CONFIG=false eslint -v && ESLINT_USE_FLAT_CONFIG=false eslint --ext '.js,.ts' --max-warnings=0 src test && npm run build:dts && npm run check:tsd",
114-
"format": "eslint --ext '.js,.ts' src test --fix",
114+
"format": "ESLINT_USE_FLAT_CONFIG=false eslint --ext '.js,.ts' src test --fix",
115115
"check:coverage": "nyc --check-coverage npm run check:node",
116116
"prepare": "node etc/prepare.js",
117117
"release": "standard-version -i HISTORY.md"

src/utils/number_utils.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,23 @@ export const NumberUtils: NumberUtils = {
8383

8484
/** Reads a little-endian 64-bit integer from source */
8585
getBigInt64LE(source: Uint8Array, offset: number): bigint {
86-
const lo = NumberUtils.getUint32LE(source, offset);
87-
const hi = NumberUtils.getUint32LE(source, offset + 4);
88-
89-
/*
90-
eslint-disable-next-line no-restricted-globals
91-
-- This is allowed since this helper should not be called unless bigint features are enabled
92-
*/
93-
return (BigInt(hi) << BigInt(32)) + BigInt(lo);
86+
// eslint-disable-next-line no-restricted-globals
87+
const hi = BigInt(
88+
source[offset + 4] +
89+
source[offset + 5] * 256 +
90+
source[offset + 6] * 65536 +
91+
(source[offset + 7] << 24)
92+
); // Overflow
93+
94+
// eslint-disable-next-line no-restricted-globals
95+
const lo = BigInt(
96+
source[offset] +
97+
source[offset + 1] * 256 +
98+
source[offset + 2] * 65536 +
99+
source[offset + 3] * 16777216
100+
);
101+
// eslint-disable-next-line no-restricted-globals
102+
return (hi << BigInt(32)) + lo;
94103
},
95104

96105
/** Reads a little-endian 64-bit float from source */

test/node/bigint.test.ts

+40
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,46 @@ describe('BSON BigInt support', function () {
105105

106106
it(description, test);
107107
}
108+
109+
it('correctly deserializes min 64 bit int (-2n**63n)', function () {
110+
expect(
111+
BSON.deserialize(Buffer.from('10000000126100000000000000008000', 'hex'), {
112+
useBigInt64: true
113+
})
114+
).to.deep.equal({ a: -(2n ** 63n) });
115+
});
116+
117+
it('correctly deserializes -1n', function () {
118+
expect(
119+
BSON.deserialize(Buffer.from('10000000126100FFFFFFFFFFFFFFFF00', 'hex'), {
120+
useBigInt64: true
121+
})
122+
).to.deep.equal({ a: -1n });
123+
});
124+
125+
it('correctly deserializes 0n', function () {
126+
expect(
127+
BSON.deserialize(Buffer.from('10000000126100000000000000000000', 'hex'), {
128+
useBigInt64: true
129+
})
130+
).to.deep.equal({ a: 0n });
131+
});
132+
133+
it('correctly deserializes 1n', function () {
134+
expect(
135+
BSON.deserialize(Buffer.from('10000000126100010000000000000000', 'hex'), {
136+
useBigInt64: true
137+
})
138+
).to.deep.equal({ a: 1n });
139+
});
140+
141+
it('correctly deserializes max 64 bit int (2n**63n -1n)', function () {
142+
expect(
143+
BSON.deserialize(Buffer.from('10000000126100FFFFFFFFFFFFFF7F00', 'hex'), {
144+
useBigInt64: true
145+
})
146+
).to.deep.equal({ a: 2n ** 63n - 1n });
147+
});
108148
});
109149

110150
describe('BSON.serialize()', function () {

0 commit comments

Comments
 (0)