Skip to content

display: fix fmt_hex_max! to not panic when given precision greater than byte length - #261

Merged
apoelstra merged 2 commits into
rust-bitcoin:masterfrom
apoelstra:2026-09/fmt-hex-max
Sep 19, 2026
Merged

apoelstra merged 2 commits into
rust-bitcoin:masterfrom
apoelstra:2026-09/fmt-hex-max

Conversation

@apoelstra

Copy link
Copy Markdown
Member

The fmt_hex_max! macro is documented to work given some source of bytes and an upper bound on the length of those bytes. However, if the source of bytes has strictly fewer bytes than claimed, and a user uses a formatter with the precision set between those values, there is a panic.

This fixes it by tracking the number of bytes consumed by the iterator. I'm not super familiar with how this is supposed to be used or what its optimization goals are, so hopefully adding this extra counter doesn't optimize that.

Fixes https://github.com/project-loupe/audit-hex-conservative/issues/2

@apoelstra

Copy link
Copy Markdown
Member Author

BTW @Kixunil do you have access to the hex-conservative Project Loupe repo? There are only 7 issues there, and at a glance they all have this flavor to them.

Probably you could fix several of them at once in a principled series of fixes, similar to what I recently did with rust-bech32.

@tcharding

Copy link
Copy Markdown
Member

This is a breaking change, right? If we don't want to break the API another solution would be to deprecate push_bytes and add push_bytes_foo that returns the usize.

Comment thread src/display.rs Outdated
encoder.put_bytes(bytes.into_iter().take(n));
&encoder.as_str()[..p]
let bytes = encoder.put_bytes(bytes.into_iter().take(n));
&encoder.as_str()[..core::cmp::min(p, bytes * 2)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the return type is a breaking change because someone could've passed the function to a function that expects a function returning (). But it's not required, just write encoder.as_str().get(..p).unwrap_or(encoder.as_str()).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, derp, I had started to write this, then tried to combine the unwrap_or branch with the p >= N branch, and then went off down a rabbit hole doing this more complicated thing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code confused me too, LOL. I was also feeling like that thing should either work or should need fewer checks and spent a bunch of time thinking it through. Maybe it needs a good comment.

@Kixunil

Kixunil commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

And yes, I do have access, I just thought I saw PRs to fix them already but after looking more closely at this one, I now see I mistook it for an unrelated issue.

@apoelstra

Copy link
Copy Markdown
Member Author

On 866ee09 successfully ran local tests

@apoelstra

Copy link
Copy Markdown
Member Author

On 16504d3 successfully ran local tests

@apoelstra
apoelstra force-pushed the 2026-09/fmt-hex-max branch 2 times, most recently from d2bd25b to a9dfebd Compare September 18, 2026 15:04

@Kixunil Kixunil left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 86fe196

@apoelstra

Copy link
Copy Markdown
Member Author

On 86fe196 successfully ran local tests

@apoelstra
apoelstra merged commit 0b5da25 into rust-bitcoin:master Sep 19, 2026
15 checks passed
@apoelstra
apoelstra deleted the 2026-09/fmt-hex-max branch September 20, 2026 14:14
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.

3 participants