Skip to content

fix(math): avoid nil internal big.Int when Unmarshal receives empty i…#26536

Open
neyy91 wants to merge 2 commits into
cosmos:mainfrom
neyy91:fix-math-unmarshal-empty-nil
Open

fix(math): avoid nil internal big.Int when Unmarshal receives empty i…#26536
neyy91 wants to merge 2 commits into
cosmos:mainfrom
neyy91:fix-math-unmarshal-empty-nil

Conversation

@neyy91

@neyy91 neyy91 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Description

Bug

LegacyDec, Int and Uint Unmarshal (math/legacy_dec.go:868,
int.go:493, uint.go:198) return a nil error on
empty input while leaving the receiver's internal big.Int nil — the d = nil
statement only reassigns the function-local pointer copy, not the caller's
value. This is asymmetric with UnmarshalJSON, which sets d.i = new(big.Int).
IsZero/IsNegative then dereference the nil internal value and panic.

Reachability (untrusted protobuf)

A DecCoin/Coin with a zero-length Amount field is valid wire data: the
generated decoder (coin.pb.go:596) calls
m.Amount.Unmarshal(dAtA[iNdEx:iNdEx]) — an empty slice — so decode succeeds
with a nil-internal Amount. DecCoin.Validate() (dec_coin.go:140)
then calls IsNegative() with no IsNil guard → nil pointer panic.
Honest encoders never emit this (MarshalTo always writes ≥1 byte), so only
crafted/malformed input is affected.

Fix

Initialize the internal big.Int to zero on empty input, matching
UnmarshalJSON. Empty input now decodes to a valid zero instead of a
panic-prone nil.

Test

TestUnmarshalEmptyIsZeroNotNil (all three types): before — IsZero/IsNegative
panic on the nil internal value; after — empty input is a usable zero.
TestUnmarshalZeroRoundTrip (all three types): a zero value survives a
Marshal/Unmarshal round trip as a usable zero. Full math module suite
green, go vet clean.

@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

PR author is not in the allowed authors list.

…nput

LegacyDec/Int/Uint Unmarshal returned nil error on empty input while
leaving the receiver's internal big.Int nil: the `d = nil` (resp. `i`,
`u`) statement only reassigned the function-local pointer copy, not the
caller's value. Methods such as IsZero/IsNegative then dereference the nil
internal value and panic.

This is reachable from untrusted protobuf: a DecCoin/Coin with a
zero-length Amount field (valid wire bytes) decodes via Amount.Unmarshal on
an empty slice, producing a nil-internal value with no error, so a later
DecCoin.Validate -> IsNegative panics.

Initialize the internal big.Int to zero on empty input, matching the
UnmarshalJSON path. Add a regression test covering all three types.
@neyy91 neyy91 force-pushed the fix-math-unmarshal-empty-nil branch from 558e332 to ef55e5a Compare June 16, 2026 00:53
@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.06%. Comparing base (c591a9f) to head (0ef4108).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #26536      +/-   ##
==========================================
+ Coverage   64.83%   65.06%   +0.22%     
==========================================
  Files         784      789       +5     
  Lines       55096    56035     +939     
==========================================
+ Hits        35724    36461     +737     
- Misses      19372    19574     +202     
Files with missing lines Coverage Δ
math/int.go 88.80% <100.00%> (ø)
math/legacy_dec.go 84.02% <100.00%> (ø)
math/uint.go 93.07% <100.00%> (ø)

... and 7 files with indirect coverage changes

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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