Skip to content

numfmt still panics on a --format precision > 65535 (incomplete fix of #12600) #13483

Description

@leeewee

A --format conversion with a floating precision above u16::MAX (65535) makes format!("{:.precision$}", …) panic with Formatting argument out of range — Rust's formatter stores precision as a u16.

This is the bug fixed by #12600 (commit bd9f32f, "numfmt: prevent panic if float precision specifier > 65535"). That fix is incomplete: it added the precision <= u16::MAX guard to only one of the three format! branches in num_prefix/the render match. Two sibling branches remain unguarded and still panic at HEAD.

Plain path (--to=none, unguarded None if opts.to == Unit::None branch):

$ numfmt --format=%.70000f 1.5
thread 'main' panicked at src/uu/numfmt/src/format.rs:631:51:
Formatting argument out of range
Aborted (core dumped)                                   # exit 134

Suffix path (--to=si, unguarded Some(s) if precision > 0 branch):

$ numfmt --to=si --format %.70000f 1000000
thread 'main' panicked at src/uu/numfmt/src/format.rs:640:46:
Formatting argument out of range
Aborted (core dumped)                                   # exit 134

Deterministic — any precision in 65536.. reaches these branches.

Root cause

src/uu/numfmt/src/format.rs, the render match. #12600 guarded the middle arm
only:

Ok(match s {
    None if opts.to == Unit::None => localize(format!(       // line 631 — UNGUARDED, panics
        "{:.precision$}",
        round_with_precision(i2, round_method, precision),
    )),
    None if is_precision_specified && precision <= u16::MAX.into() => {   // line 635 — guarded by #12600
        let i2 = round_with_precision(i2, round_method, 0);
        localize(format!("{i2:.precision$}"))
    }
    None => localize(format!("{i2:.0}")),
    Some(s) if precision > 0 => localize(format!(           // line 640 — UNGUARDED, panics
        "{i2:.precision$}{unit_separator}{}",
        DisplayableSuffix(s, opts.to),
    )),
    Some(s) if is_precision_specified => {}
})
  • The None if opts.to == Unit::None arm (line 631) formats with the raw precision and no u16 bound.
  • The Some(s) if precision > 0 suffix arm (line 640) does the same.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions