Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UpperHex formatting might panic #126425

Closed
ZhekaS opened this issue Jun 13, 2024 · 6 comments · Fixed by #132473
Closed

UpperHex formatting might panic #126425

ZhekaS opened this issue Jun 13, 2024 · 6 comments · Fixed by #132473
Labels
A-panic Area: Panicking machinery C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@ZhekaS
Copy link

ZhekaS commented Jun 13, 2024

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.

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jun 13, 2024
@zachs18
Copy link
Contributor

zachs18 commented Jun 13, 2024

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
Copy link
Author

ZhekaS commented Jun 13, 2024

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
Copy link
Contributor

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

@rustbot rustbot added A-panic Area: Panicking machinery C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs Relevant to the library team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jun 14, 2024
ZhekaS pushed a commit to ZhekaS/rust that referenced this issue Nov 1, 2024
Fixes rust-lang#126425

Replace the potentially panicking `[]` indexing with `get_unchecked()`
to prevent linking with panic-related code.
@clubby789
Copy link
Contributor

Based on minimizing the code to:

pub fn fmt_int(buf: &mut [u8; 128], mut x: u128) -> &[u8] {
    let mut curr = buf.len();
    for byte in buf.iter_mut().rev() {
        if *byte == 0 { break; }
        curr -= 1;
    }
    &buf[curr..]
}

it seems like LLVM should be removing this panic: https://alive2.llvm.org/ce/z/UJHdEr

@ericlagergren
Copy link

Based on minimizing the code to:

pub fn fmt_int(buf: &mut [u8; 128], mut x: u128) -> &[u8] {
    let mut curr = buf.len();
    for byte in buf.iter_mut().rev() {
        if *byte == 0 { break; }
        curr -= 1;
    }
    &buf[curr..]
}

it seems like LLVM should be removing this panic: https://alive2.llvm.org/ce/z/UJHdEr

/might/ be related to #127553

@ZhekaS
Copy link
Author

ZhekaS commented Nov 4, 2024

Based on minimizing the code to:

pub fn fmt_int(buf: &mut [u8; 128], mut x: u128) -> &[u8] {
let mut curr = buf.len();
for byte in buf.iter_mut().rev() {
if *byte == 0 { break; }
curr -= 1;
}
&buf[curr..]
}
it seems like LLVM should be removing this panic: https://alive2.llvm.org/ce/z/UJHdEr

I think in the original code the compiler might not be able to infer that curr does not underflow, as the assumption is that the max T width is 128 bits, but the compiler does not make such an assumption (as @zachs18 mentions above). I wonder if adding the assertion on the width would give it the necessary hint. Need to test it out, as it might be a better solution than replacing by get_unchecked() whatsoever
Upd:
It looks like the trait T is bound to (DisplayInt) does not provide any type width information, so for compile-time checks more changes will be required.

workingjubilee added a commit to workingjubilee/rustc that referenced this issue Nov 4, 2024
…joboet

[core/fmt] Replace checked slice indexing by unchecked to support panic-free code

Fixes rust-lang#126425

Replace the potentially panicking `[]` indexing with `get_unchecked()` to prevent linking with panic-related code.
tgross35 added a commit to tgross35/rust that referenced this issue Nov 5, 2024
…joboet

[core/fmt] Replace checked slice indexing by unchecked to support panic-free code

Fixes rust-lang#126425

Replace the potentially panicking `[]` indexing with `get_unchecked()` to prevent linking with panic-related code.
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Nov 5, 2024
…joboet

[core/fmt] Replace checked slice indexing by unchecked to support panic-free code

Fixes rust-lang#126425

Replace the potentially panicking `[]` indexing with `get_unchecked()` to prevent linking with panic-related code.
@bors bors closed this as completed in 02a1ab8 Nov 5, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Nov 5, 2024
Rollup merge of rust-lang#132473 - ZhekaS:core_fmt_radix_no_panic, r=joboet

[core/fmt] Replace checked slice indexing by unchecked to support panic-free code

Fixes rust-lang#126425

Replace the potentially panicking `[]` indexing with `get_unchecked()` to prevent linking with panic-related code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-panic Area: Panicking machinery C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants