Skip to content

Commit 9787950

Browse files
committed
fix(datastreams): correct varint encoding when a group shifts down to 0x80
encodeVarintInto exited its 7-bit loop while the remaining value was still 0x80 and then masked the continuation bit off the final byte, dropping that bit. Every value whose zig-zag form shifts down to exactly 0x80 encoded as a truncated number: 64, then a band of 2 ** (exponent - 7) values above every seventh power of two. Pathway contexts carry millisecond epoch timestamps, which enter the next affected band on 2039-09-07 and leave it on 2040-03-24.
1 parent ae08daf commit 9787950

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

packages/dd-trace/src/datastreams/encoding.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function encodeVarintInto (target, offset, value) {
4040
let i = offset
4141
const limit = offset + maxVarLen64 - 1
4242
// if first byte is 1, the number is negative in javascript, but we want to interpret it as positive
43-
while ((high !== 0 || low < 0 || low > 0x80) && i < limit) {
43+
while ((high !== 0 || low < 0 || low > 0x7F) && i < limit) {
4444
target[i] = (low & 0x7F) | 0x80
4545
low >>>= 7
4646
low |= (high & 0x7F) << 25

packages/dd-trace/test/datastreams/encoding.spec.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ describe('encoding', () => {
5353
assert.strictEqual(negativeBytes.length, 0)
5454
})
5555

56+
it('encoding then decoding should be a no op when a group shifts down to 0x80', () => {
57+
// The zig-zag value shifts down to exactly 0x80 for `2 ** exponent` and the
58+
// `2 ** (exponent - 7)` values above it. Math.floor(Number.MAX_SAFE_INTEGER / 2)
59+
// spans seven 7-bit groups, so there are seven such bands.
60+
for (let exponent = 6; exponent <= 48; exponent += 7) {
61+
const base = 2 ** exponent
62+
const bandTop = base + 2 ** Math.max(exponent - 7, 0) - 1
63+
64+
for (const n of new Set([base, bandTop, -base, -bandTop])) {
65+
const encoded = encodeVarint(n)
66+
const [decoded, bytes] = decodeVarint(encoded)
67+
assert.strictEqual(decoded, n)
68+
assert.strictEqual(bytes.length, 0)
69+
}
70+
}
71+
72+
assert.deepStrictEqual([...encodeVarint(2 ** 6)], [128, 1])
73+
})
74+
5675
it('encoding a number bigger than Max safe int fails.', () => {
5776
const n = Number.MAX_SAFE_INTEGER + 10
5877
const encoded = encodeVarint(n)

0 commit comments

Comments
 (0)