about summary refs log tree commit diff
path: root/compiler/rustc_parse_format/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-10-14 13:41:40 +0000
committerbors <bors@rust-lang.org>2022-10-14 13:41:40 +0000
commitee1c3b385b6673b6ef37d80dfabe048e993c2ae2 (patch)
tree96f1be9a61f9d2fed454a885e195e2373725aba4 /compiler/rustc_parse_format/src
parent9b0a099dfc9a97ecd10adb319396c731c4b2d169 (diff)
parentb9e85bf60ab4376a321f03078c06cd95ea5143ef (diff)
downloadrust-ee1c3b385b6673b6ef37d80dfabe048e993c2ae2.tar.gz
rust-ee1c3b385b6673b6ef37d80dfabe048e993c2ae2.zip
Auto merge of #102529 - colinba:master, r=joshtriplett
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
Diffstat (limited to 'compiler/rustc_parse_format/src')
-rw-r--r--compiler/rustc_parse_format/src/lib.rs28
-rw-r--r--compiler/rustc_parse_format/src/tests.rs15
2 files changed, 39 insertions, 4 deletions
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index df22d79f82e..1394993abad 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -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 }
     }
 
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 2f8c229c68f..3f9cb149b53 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -58,6 +58,21 @@ fn invalid06() {
 }
 
 #[test]
+fn invalid_position() {
+    musterr("{18446744073709551616}");
+}
+
+#[test]
+fn invalid_width() {
+    musterr("{:18446744073709551616}");
+}
+
+#[test]
+fn invalid_precision() {
+    musterr("{:.18446744073709551616}");
+}
+
+#[test]
 fn format_nothing() {
     same(
         "{}",