rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.81k stars 12.5k forks source link

UpperHex formatting might panic #126425

Open ZhekaS opened 3 months ago

ZhekaS commented 3 months ago

When writing non-panicking code, it is impossible to use the "{:X}" format specifier as the impl core::fmt::UpperHex for usize and similar code might panic. It seems that it is because the GenericRadix::fmt_int method is using slice indexing notation here:

    let buf = &buf[curr..];

This seem to be easily avoidable by replacing it with buf.get(curr..) and some error handling.

zachs18 commented 3 months ago

curr is initialized to buf.len(), and is only ever decremented, so as long as the decrements do not overflow, &buf[curr..] cannot panic.

buf has length 128, and curr is decremented exactly once for each digit, so for curr to overflow would require that the number to be formatted have more that 128 digits in the particular base (2, 8, or 16), which is currently not possible since u128 is the largest fixed-width integer type, and usize::BITS <= 64 on all currently supported platforms.

I suppose a const _: () = assert!(T::BITS <= 128) or similar could be added to this code to ensure that any future platform with usize::BITS > 128 would fail to compile unless this code was updated to account for it, (but I imagine there are several other places in the standard library which makes a similar assumption).

ZhekaS commented 3 months ago

curr is initialized to buf.len(), and is only ever decremented, so as long as the decrements do not overflow, &buf[curr..] cannot panic.

It's OK that it won't panic in practice, but the compiler is unable to prove it, so it is generating the panic code and linking with panic-related functionality which is desirable to avoid. That is, using crates such as no_panics_whatsoever or similar functionality by other means won't work.

veera-sivarajan commented 3 months ago

@rustbot label -needs-triage +T-libs +A-panic +C-enhancement