Skip to content

Commit 2563d82

Browse files
committed
fix(core/cbor): calculation of bigInteger offset
1 parent bb7975e commit 2563d82

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed

.changeset/clever-shirts-prove.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/core": patch
3+
---
4+
5+
fix offset calculation when decoding bigInteger in CBOR

packages/core/src/submodules/cbor/cbor-decode.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,22 +129,26 @@ export function decode(at: Uint32, to: Uint32): CborValueType {
129129
for (let i = start; i < start + length; ++i) {
130130
b = (b << BigInt(8)) | BigInt(payload[i]);
131131
}
132-
133-
_offset = offset + length;
132+
// the new offset is the sum of:
133+
// 1. the local major offset (1)
134+
// 2. the offset of the decoded count of the bigInteger
135+
// 3. the length of the data bytes of the bigInteger
136+
_offset = offset + _offset + length;
134137
return minor === 3 ? -b - BigInt(1) : b;
135138
} else if (minor === 4) {
136139
const decimalFraction = decode(at + offset, to);
137140
const [exponent, mantissa] = decimalFraction;
138141
const s = mantissa.toString();
139142
const numericString = exponent === 0 ? s : s.slice(0, s.length + exponent) + "." + s.slice(exponent);
140-
143+
// no new _offset is set here, because
144+
// the call to decode for the decimalFraction
145+
// has set it.
141146
return new NumericValue(numericString, "bigDecimal");
142147
} else {
143148
const value = decode(at + offset, to);
144149
const valueOffset = _offset;
145150

146151
_offset = offset + valueOffset;
147-
148152
return tag({ tag: castBigInt(unsignedInt), value });
149153
}
150154
}

packages/core/src/submodules/cbor/cbor.spec.ts

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { cbor } from "./cbor";
99
import { bytesToFloat16 } from "./cbor-decode";
1010
import { tagSymbol } from "./cbor-types";
1111
import { dateToTag } from "./parseCborBody";
12+
import { nv } from "../serde";
1213

1314
// syntax is ESM but the test target is CJS.
1415
const here = __dirname;
@@ -219,12 +220,23 @@ describe("cbor", () => {
219220
name: "object containing big numbers",
220221
data: {
221222
map: {
222-
items: [BigInt(1e80)],
223+
items: [BigInt(1e80), BigInt(1e80), nv("0.0000000001234000000001234"), nv("0.0000000001234000000001234")],
224+
bigint: BigInt(1e80),
225+
bigDecimal: nv("0.0000000001234000000001234"),
223226
},
224227
},
225228
cbor: allocByteArray([
226-
161, 99, 109, 97, 112, 161, 101, 105, 116, 101, 109, 115, 129, 194, 88, 34, 3, 95, 157, 234, 62, 31, 107, 224,
227-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
229+
161, 99, 109, 97, 112, 163, 101, 105, 116, 101, 109, 115, 132, 194, 88, 34, 3, 95, 157, 234, 62, 31, 107, 224,
230+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 88, 34, 3, 95, 157, 234, 62,
231+
31, 107, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 102, 115, 116,
232+
114, 105, 110, 103, 120, 27, 48, 46, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 50, 51, 52, 48, 48, 48, 48, 48, 48,
233+
48, 48, 49, 50, 51, 52, 100, 116, 121, 112, 101, 106, 98, 105, 103, 68, 101, 99, 105, 109, 97, 108, 162, 102,
234+
115, 116, 114, 105, 110, 103, 120, 27, 48, 46, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 50, 51, 52, 48, 48, 48,
235+
48, 48, 48, 48, 48, 49, 50, 51, 52, 100, 116, 121, 112, 101, 106, 98, 105, 103, 68, 101, 99, 105, 109, 97, 108,
236+
102, 98, 105, 103, 105, 110, 116, 194, 88, 34, 3, 95, 157, 234, 62, 31, 107, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 98, 105, 103, 68, 101, 99, 105, 109, 97, 108, 162, 102,
238+
115, 116, 114, 105, 110, 103, 120, 27, 48, 46, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 50, 51, 52, 48, 48, 48,
239+
48, 48, 48, 48, 48, 49, 50, 51, 52, 100, 116, 121, 112, 101, 106, 98, 105, 103, 68, 101, 99, 105, 109, 97, 108,
228240
]),
229241
},
230242
];
@@ -305,6 +317,60 @@ describe("cbor", () => {
305317
}
306318
});
307319

320+
it.only("should round-trip sequences of big numbers", () => {
321+
const sequence = {
322+
map: {
323+
items1: [
324+
BigInt(1e20),
325+
BigInt(2e30),
326+
BigInt(3e40),
327+
BigInt(4e50),
328+
BigInt(5e60),
329+
BigInt(6e70),
330+
BigInt(7e80),
331+
BigInt(8e90),
332+
],
333+
items2: [BigInt(1e20), BigInt(2e30), nv("0.0000000001123434"), nv("0.000000000126781234")],
334+
items3: [nv("0.0000000001234000000001234"), nv("0.00000000678678001234"), BigInt(1e20), BigInt(2e30)],
335+
items4: [
336+
BigInt(1e20),
337+
BigInt(2e30),
338+
nv("0.0000000001234000000001234"),
339+
nv("0.0000067867867801234"),
340+
BigInt(1e20),
341+
BigInt(2e30),
342+
nv("0.0000000001234000000001234"),
343+
nv("0.000000000123678678678234"),
344+
],
345+
items5: [
346+
nv("0.0000000001234000000001234"),
347+
nv("0.00006786781234678678678"),
348+
BigInt(1e20),
349+
BigInt(2e30),
350+
nv("0.0000000001234000000001234"),
351+
nv("0.000000000123400000087678634"),
352+
BigInt(1e20),
353+
BigInt(2e30),
354+
],
355+
items6: [
356+
nv("0.0000000001234000000001234"),
357+
nv("0.00006786781234678678678"),
358+
nv("0.0000000001234000000001234"),
359+
nv("0.000000000123400000087678634"),
360+
nv("0.0000000001234000000001234"),
361+
nv("0.00006786781234678678678"),
362+
nv("0.0000000001234000000001234"),
363+
nv("0.000000000123400000087678634"),
364+
],
365+
},
366+
};
367+
368+
const serialized = cbor.serialize(sequence);
369+
const deserialized = cbor.deserialize(serialized);
370+
371+
expect(deserialized).toEqual(sequence);
372+
});
373+
308374
it("should throw an error if serializing a tag with missing properties", () => {
309375
expect(() =>
310376
cbor.serialize({

0 commit comments

Comments
 (0)