Skip to content

fix(thrift): sign-extend negative I64 on read; support bigint/BOOL/BYTE/I16 collection elements - #217

Open
nezumi0627 wants to merge 1 commit into
evex-dev:mainfrom
nezumi0627:fix/thrift-i64-and-byte-types
Open

fix(thrift): sign-extend negative I64 on read; support bigint/BOOL/BYTE/I16 collection elements#217
nezumi0627 wants to merge 1 commit into
evex-dev:mainfrom
nezumi0627:fix/thrift-i64-and-byte-types

Conversation

@nezumi0627

Copy link
Copy Markdown
Contributor

Summary

Four related correctness bugs in the Thrift read/write layer, each verified with a failing round-trip before the fix:

1. Negative I64 values decoded as huge positive numbers (read.ts)

The reader interpreted raw two's-complement octets as an unsigned hex number:

const value = BigInt("0x" + bin.toString("hex")); // unsigned!

The write side was already fixed for negatives (asUintN, pinned by write.test.ts: -5nfffffffffffffffb on the wire), but a round-trip failed: reading -5n back gave 18446744073709551611n. The reader now sign-extends when the top bit is set.

2. bigint I64 rejected inside LIST/SET/MAP elements (write.ts)

The #193 fix (bigint-safe Int64 encoding) was only applied to field-level writeValue. Collection elements go through writeValue_, which threw:

writeStruct([[10, 1, 618946633287860670n]], P3);         // ok
writeStruct([[15, 1, [10, [618946633287860670n]]]], P3); // TypeError: ftype=10: value is not number

This matters for e.g. message IDs passed as list elements. writeValue_ now mirrors the field-level encoding.

3. BYTE (3) and I16 (6) fields silently dropped / corrupt frames

Both types are declared in NestedArray but fell through to default: in both writers — no error, no bytes:

  • Field level: [[3, 1, 255]] produced an empty struct (field vanished silently).
  • Element level: writeListBegin(etype=3, count=3) was written and then nothing per element, producing a structurally corrupt frame that claims 3 elements.
  • The reader also skipped both types (readValue returned undefined).

BYTE/I16 are now written and read properly on both sides.

4. BOOL accepted numbers at field level but not element level

writeValue accepts boolean | number, writeValue_ required strict boolean. Now consistent.

Testing

  • Reproduced every case with a scratch harness before fixing (negative round-trip returned 18446744073709551611n; bigint element threw; BYTE field absent from wire; BYTE list emitted count=3 with zero elements).
  • Added regression tests to write.test.ts (5 new tests): negative-I64 round-trip on both protocols, bigint-in-collection encoding, BYTE/I16 field wire hex pin, BYTE/I16 collection round-trip, numeric-BOOL acceptance.
  • Full suite: deno test --allow-all — 219 passed, 0 failed.
  • deno fmt / deno lint clean on touched files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant