Skip to content

pxf-android: skip a field whose wire type does not match its kind - #181

Merged
trendvidia merged 4 commits into
mainfrom
pxf-android/wire-type-160
Nov 3, 2026
Merged

trendvidia merged 4 commits into
mainfrom
pxf-android/wire-type-160

Conversation

@bfrancojr

Copy link
Copy Markdown
Collaborator

Fixes #160

The lite tier's wire reader now skips a field whose wire type does not match its declared kind, as protowire-go and the full tier do. Before, it read the field with its kind's reader anyway. The bytes got misread from there to the end of the message, so lite either rejected the message or printed a wrong value. For example, 3a050d01000000 is an Int64Value whose field 1 arrives as fixed32. Lite rejected it with invalid tag (zero), while Go prints i64_w = 0.

What changed (LiteWireReader)

  • Each field read in a message is checked against its kind's wire type. That covers singular, repeated and map fields, and map entries too, since they are read the same way. A mismatch is skipped with skipField, as an unknown field would be.
  • A repeated packable field still takes both forms: one packed (length-delimited) record, or one record per element. That is not a mismatch.
  • Every well-known payload read as a literal gets the same check, per field: Timestamp, Duration, the nine wrappers, pxf.BigInt, Decimal, BigFloat and Secret. In readDecimal that is a one-line change to the switch expression. It touches no other part of the method.

Also fixed (its own commit, a consequence of the above)

  • A map entry with no key or no value now gets that field's zero value. Before, both came back as the string "". The case shows up whenever a mistyped key or value is skipped, and also when an encoder leaves it out. by_int = { "": "x" } is now { 0: "x" }, and stamps = { a: "" } is now { a: 1970-01-01T00:00:00Z }, matching Go.

Evidence

  • The issue's input, --format pb-text --schema text.v1.WellKnown against the spec's testdata/text/text.proto:
    • before: check-decode-android printed reject: 1:1: malformed wire: Protocol message contained an invalid tag (zero). and exited 1. Go check_decode (protowire-go 7465f91) printed i64_w = 0 and exited 0. The full tier check-decode printed i64_w = 0 and exited 0.
    • after: check-decode-android prints i64_w = 0 and exits 0.
  • A probe set of 62 wire messages, run through Go and lite with the output and exit code compared. It covers each wire type (varint, fixed32, fixed64, length-delimited, group) arriving on a field of another kind: scalars, a nested message, a oneof, optional, repeated (packed and unpacked), map keys and values, and a field inside each well-known payload. It also has controls with well-typed fields.
    • lite at the branch base (c81b3fa): 5 of 62 match Go.
    • lite on this branch: 62 of 62 match Go. The full tier matches Go on 62 of 62 too.
  • The probes are now a test, pxf-android-codegen-it WireTypeLiteTest: 63 tests, with the expected text taken from Go's output. With main's LiteWireReader put back, 58 of the 63 fail. The 5 that pass are the controls.
  • ./gradlew build: BUILD SUCCESSFUL. Summed from the test-result XML: 780 tests, 0 failures, 0 errors, 0 skipped.
  • The spec's text gate, cross_text_check.sh (protowire 09f5653; Go, java, java-lite): Ran 168 (port, case) pairs across 3 ports. ✓ Every port that ran writes the golden text.

The builds used the plugin ref pinned in gradle.properties (-PpxfJavaMeta.repo=<nonexistent>). The sibling ../protowire checkout is on another branch, and its plugin currently generates SbeTextSbeMeta code that does not compile.

Filed

LiteWireReader read every known field with its kind's reader, whatever wire
type the tag carried. A mistyped field was then misread and the rest of the
message with it: 3a050d01000000, an Int64Value whose field 1 arrives as
fixed32, failed with 'invalid tag (zero)' where protowire-go and the full
tier print i64_w = 0. The field is now skipped as unknown, in a message, a
map entry and every well-known payload. A repeated packable field still
takes either the packed or the unpacked record.
A map entry that lacks its key or its value, because the encoder left it
out or because the reader now skips it as mistyped (#160), came back as the
string "": by_int = { "": "x" } where protobuf-go prints { 0: "x" },
and stamps = { a: "" } where it prints the epoch. The missing field is now
read from a zero encoding of its kind, so an integer key is 0, a bool key
false, a message value empty and a well-known value its zero literal.
…mistyped fields (#160)

62 wire messages against text.proto, each with protowire-go's pb-text
output for it: every wire type arriving on a field of another kind, in a
message, a repeated field, a map entry and each well-known payload, plus
packed and unpacked repeated records and map entries missing a key or a
value. On main's reader 58 of the 63 tests fail.
@trendvidia
trendvidia merged commit 0fa0156 into main Nov 3, 2026
4 checks passed
@trendvidia
trendvidia deleted the pxf-android/wire-type-160 branch November 3, 2026 10:59
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.

pxf-android: LiteWireReader rejects a mistyped field that Go skips

2 participants