Skip to content

Read the REAL mantissa as an unsigned integer and check exponent scaling - #146

Open
dzatona wants to merge 1 commit into
rusticata:masterfrom
dzatona:fix-real-mantissa-accumulator
Open

Read the REAL mantissa as an unsigned integer and check exponent scaling#146
dzatona wants to merge 1 commit into
rusticata:masterfrom
dzatona:fix-real-mantissa-accumulator

Conversation

@dzatona

@dzatona dzatona commented Aug 16, 2026

Copy link
Copy Markdown

Addresses the first and third defects in #143. The exponent-format defect is
left alone — that one changes which inputs are accepted, so it is a separate
decision.

Two changes in decode_real:

The mantissa is accumulated into u64 instead of i64, with the sign applied
at the conversion to f64.
X.690 8.5.7.5 defines N as an unsigned binary
number, so bit 63 of an eight-octet mantissa is a value bit, not a sign bit.
Today 09 0a 80 00 80 00 00 00 00 00 00 01 decodes as
-9.223372036854776e18 in every profile; with this it decodes positive. The same
change removes the negation overflow, since there is no longer a negation of
i64::MIN to overflow.

u64 rather than i128 because the existing rem.len() > 8 guard already caps
N at eight octets, so u64 represents every mantissa the crate accepts, exactly.

checked_mul on the base-8 and base-16 exponent scaling, returning
InvalidValue { msg: "Exponent out of range (REAL)" }. This is reachable on
BER-conforming input today — a 37-byte value with X = 32 gets its exponent
misread as 20 01 00 00, and e * 4 leaves i32 before the mantissa-length
guard is consulted — and it stays reachable if the exponent-format defect is
fixed, because X = 4 remains legal and a four-octet exponent spans i32. So
this part stands on its own regardless of what happens to the format handling.

Three tests in tests/ber.rs, in the style of the existing from_ber_real_*
ones: the unsigned mantissa, the most-negative mantissa, and four inputs that
must be rejected for exponent range — the two short malformed ones plus both
minimal BER-conforming forms, 48 bytes for base 8 and 37 for base 16. All three
fail against an unpatched real.rs.

cargo fmt --check, cargo clippy --all-features --all-targets -- -D warnings
and cargo test --all-features are clean: 466 tests, no existing test changed.
Both build profiles now agree on every input I have, which they did not before.

The CI failures on this branch are the compile_fail trybuild mismatch already
present on master — a rustc diagnostic reworded since the .stderr was
recorded. Not related to this change.

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