Skip to content

Commit

Permalink
Auto merge of #102529 - colinba:master, r=joshtriplett
Browse files Browse the repository at this point in the history
Detect and reject out-of-range integers in format string literals

Until now out-of-range integers in format string literals were silently ignored. They wrapped around to zero at usize::MAX, producing unexpected results.

When using debug builds of rustc, such integers in format string literals even cause an 'attempt to add with overflow' panic in rustc.

Fix this by producing an error diagnostic for integers in format string literals which do not fit into usize.

Fixes #102528
  • Loading branch information
bors committed Oct 14, 2022
2 parents 9b0a099 + b9e85bf commit ee1c3b3
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 5 deletions.
28 changes: 24 additions & 4 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,20 +740,40 @@ impl<'a> Parser<'a> {
word
}

/// Optionally parses an integer at the current position. This doesn't deal
/// with overflow at all, it's just accumulating digits.
fn integer(&mut self) -> Option<usize> {
let mut cur = 0;
let mut cur: usize = 0;
let mut found = false;
let mut overflow = false;
let start = self.current_pos();
while let Some(&(_, c)) = self.cur.peek() {
if let Some(i) = c.to_digit(10) {
cur = cur * 10 + i as usize;
let (tmp, mul_overflow) = cur.overflowing_mul(10);
let (tmp, add_overflow) = tmp.overflowing_add(i as usize);
if mul_overflow || add_overflow {
overflow = true;
}
cur = tmp;
found = true;
self.cur.next();
} else {
break;
}
}

if overflow {
let end = self.current_pos();
let overflowed_int = &self.input[start..end];
self.err(
format!(
"integer `{}` does not fit into the type `usize` whose range is `0..={}`",
overflowed_int,
usize::MAX
),
"integer out of range for `usize`",
self.span(start, end),
);
}

if found { Some(cur) } else { None }
}

Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_parse_format/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ fn invalid06() {
musterr("{:>>>}")
}

#[test]
fn invalid_position() {
musterr("{18446744073709551616}");
}

#[test]
fn invalid_width() {
musterr("{:18446744073709551616}");
}

#[test]
fn invalid_precision() {
musterr("{:.18446744073709551616}");
}

#[test]
fn format_nothing() {
same(
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@
//! - `text` must not contain any `'{'` or `'}'` characters,
//! - `ws` is any character for which [`char::is_whitespace`] returns `true`, has no semantic
//! meaning and is completely optional,
//! - `integer` is a decimal integer that may contain leading zeroes and
//! - `integer` is a decimal integer that may contain leading zeroes and must fit into an `usize` and
//! - `identifier` is an `IDENTIFIER_OR_KEYWORD` (not an `IDENTIFIER`) as defined by the [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html).
//!
//! # Formatting traits
Expand Down

0 comments on commit ee1c3b3

Please sign in to comment.