Skip to content

Commit f369db2

Browse files
authored
Fix 64-bit BigInt sign handling (#135)
* Fix 64-bit BigInt sign handling * add test * update submodule commit
1 parent b48a469 commit f369db2

3 files changed

Lines changed: 24 additions & 6 deletions

File tree

src/datatypes/numeric.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
const { PartialReadError } = require('../utils')
22

3-
class BigIntExtended extends Array {
3+
class SignedBigInt extends Array {
44
valueOf () { return BigInt.asIntN(64, BigInt(this[0]) << 32n) | BigInt.asUintN(32, BigInt(this[1])) }
5+
toString () { return this.valueOf().toString() }
6+
[Symbol.for('nodejs.util.inspect.custom')] () { return this.valueOf() }
7+
}
8+
9+
class UnsignedBigInt extends Array {
10+
valueOf () { return BigInt.asUintN(64, BigInt(this[0]) << 32n) | BigInt.asUintN(32, BigInt(this[1])) }
11+
toString () { return this.valueOf().toString() }
512
[Symbol.for('nodejs.util.inspect.custom')] () { return this.valueOf() }
613
}
714

815
function readI64 (buffer, offset) {
916
if (offset + 8 > buffer.length) { throw new PartialReadError() }
1017
return {
11-
value: new BigIntExtended(buffer.readInt32BE(offset), buffer.readInt32BE(offset + 4)),
18+
value: new SignedBigInt(buffer.readInt32BE(offset), buffer.readInt32BE(offset + 4)),
1219
size: 8
1320
}
1421
}
@@ -26,7 +33,7 @@ function writeI64 (value, buffer, offset) {
2633
function readLI64 (buffer, offset) {
2734
if (offset + 8 > buffer.length) { throw new PartialReadError() }
2835
return {
29-
value: new BigIntExtended(buffer.readInt32LE(offset + 4), buffer.readInt32LE(offset)),
36+
value: new SignedBigInt(buffer.readInt32LE(offset + 4), buffer.readInt32LE(offset)),
3037
size: 8
3138
}
3239
}
@@ -44,7 +51,7 @@ function writeLI64 (value, buffer, offset) {
4451
function readU64 (buffer, offset) {
4552
if (offset + 8 > buffer.length) { throw new PartialReadError() }
4653
return {
47-
value: new BigIntExtended(buffer.readUInt32BE(offset), buffer.readUInt32BE(offset + 4)),
54+
value: new UnsignedBigInt(buffer.readUInt32BE(offset), buffer.readUInt32BE(offset + 4)),
4855
size: 8
4956
}
5057
}
@@ -62,7 +69,7 @@ function writeU64 (value, buffer, offset) {
6269
function readLU64 (buffer, offset) {
6370
if (offset + 8 > buffer.length) { throw new PartialReadError() }
6471
return {
65-
value: new BigIntExtended(buffer.readUInt32LE(offset + 4), buffer.readUInt32LE(offset)),
72+
value: new UnsignedBigInt(buffer.readUInt32LE(offset + 4), buffer.readUInt32LE(offset)),
6673
size: 8
6774
}
6875
}

test/dataTypes/datatypes.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ function testValue (type, value, buffer) {
2424
if (value === null) { assert.ok(actualResult.data === undefined) } else { expect(actualResult.data).to.deep.equal(value) }
2525
expect(actualResult.metadata.size).to.deep.equal(buffer.length)
2626
})
27+
28+
if (type === 'i64' || type === 'u64') {
29+
it('reads bigint correctly ' + type, function () {
30+
const [top, lower] = value.map(BigInt)
31+
const joined = type === 'i64' ? BigInt.asIntN(64, (top << 32n) | lower) : BigInt.asUintN(64, (top << 32n) | lower)
32+
// read
33+
const actualResult = proto.parsePacketBuffer(type, buffer)
34+
expect(actualResult.data.valueOf() === joined)
35+
expect(actualResult.metadata.size).to.deep.equal(buffer.length)
36+
})
37+
}
2738
}
2839

2940
function testType (type, values) {

0 commit comments

Comments
 (0)