Skip to content

Format: fixes integer wraparound when parsing numbers - #2696

Merged
CarterLi merged 1 commit into
fastfetch-cli:devfrom
arxhr007:fix/format-integer-overflow
Oct 31, 2026
Merged

CarterLi merged 1 commit into
fastfetch-cli:devfrom
arxhr007:fix/format-integer-overflow

Conversation

@arxhr007

Copy link
Copy Markdown
Contributor

Summary

Numbers in a format string that don't fit in 32 bits were truncated, so they could turn into a valid value:

Format Before After
{4294967297} (2 arguments) the first argument the placeholder, as for any invalid index
{4294967296} the next argument (read as {}) the placeholder
{$4294967297} the first constant the placeholder
{1~4294967297} on 12345 67890 2345 67890 (read as {1~1}) empty
{1:-4294967296} on 12345 67890 empty (read as {1:0}) 12345 67890

The causes were (uint32_t) strtoul(...) in getArgumentIndex() and (int32_t) strtol(...) for the constant index and for the start, end and length of ~, :, <, > and |. On 64-bit platforms long is wider than the type it was cast to.

There is also a signed overflow: for a negative length, {1:-2147483648} negates INT32_MIN to get the ellipsis length. UBSan reports it:

format.c:586:29: runtime error: negation of -2147483648 cannot be represented in type 'int'

Related issue (required for new logos for new distros)

Not a logo. No issue, it is a small fix in the same code as #2669.

Changes

  • src/common/impl/format.c: new strToInt32() that clamps instead of wrapping, used for the constant index, the substring start and end and the length. getArgumentIndex() compares the unsigned long before narrowing. INT32_MIN is no longer negated.
  • tests/format.c: cases for each of the above. The first one fails on the old code.
  • CHANGELOG.md: bugfix entry.

Screenshots

Not a visual change.

Checklist

  • I have tested my changes locally.

Built with -DBUILD_TESTS=On -DENABLE_ASAN=On and -fsanitize=undefined; all 19 tests pass without sanitizer reports.

Numbers that don't fit in 32 bits were truncated, so `{4294967297}` was read
as `{1}`, `{4294967296}` as the next argument, and `{$4294967297}` as the
first constant. The same applied to the start, end and length of `~`, `:`, `<`,
`>` and `|`. Clamp them instead, so that they stay out of range.

Also avoid negating INT32_MIN for the ellipsis length of `{1:-2147483648}`,
which is a signed integer overflow.
@CarterLi
CarterLi merged commit d6c15e1 into fastfetch-cli:dev Oct 31, 2026
26 checks passed
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.

2 participants