Skip to content

Commit 1c90b9f

Browse files
committed
Auto merge of #125004 - pymongo:issue-125002, r=estebank
Fix println! ICE when parsing percent prefix number This PR fixes #125002 ICE occurring, for example, with `println!("%100000", 1)` or `println!("% 100000", 1)`. ## Test Case/Change Explanation The return type of `Num::from_str` has been changed to `Option<Self>` to handle errors when parsing large integers fails. 1. The first `println!` in the test case covers the change of the first `Num::from_str` usage in `format_foreign.rs:426`. 2. The second `println!` in the test case covers the change of the second `Num::from_str` usage in line 460. 3. The 3rd to 5th `Num::from_str` usages behave the same as before. The 3rd usage would cause an ICE when `num > u16::MAX` in the previous version, but this commit does not include a fix for the ICE in `println!("{:100000$}")`. I think we need to emit an error in the compiler and have more discussion in another issue/PR.
2 parents 36c0a6d + 582fd1f commit 1c90b9f

File tree

3 files changed

+49
-9
lines changed

3 files changed

+49
-9
lines changed

Diff for: compiler/rustc_builtin_macros/src/format_foreign.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,13 @@ pub(crate) mod printf {
263263
}
264264

265265
impl Num {
266-
fn from_str(s: &str, arg: Option<&str>) -> Self {
266+
fn from_str(s: &str, arg: Option<&str>) -> Option<Self> {
267267
if let Some(arg) = arg {
268-
Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`")))
268+
arg.parse().ok().map(|arg| Num::Arg(arg))
269269
} else if s == "*" {
270-
Num::Next
270+
Some(Num::Next)
271271
} else {
272-
Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`")))
272+
s.parse().ok().map(|num| Num::Num(num))
273273
}
274274
}
275275

@@ -421,7 +421,10 @@ pub(crate) mod printf {
421421
state = Prec;
422422
parameter = None;
423423
flags = "";
424-
width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
424+
width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
425+
if width.is_none() {
426+
return fallback();
427+
}
425428
move_to!(end);
426429
}
427430
// It's invalid, is what it is.
@@ -452,7 +455,10 @@ pub(crate) mod printf {
452455
'1'..='9' => {
453456
let end = at_next_cp_while(next, char::is_ascii_digit);
454457
state = Prec;
455-
width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
458+
width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
459+
if width.is_none() {
460+
return fallback();
461+
}
456462
move_to!(end);
457463
}
458464
_ => {
@@ -468,7 +474,7 @@ pub(crate) mod printf {
468474
match end.next_cp() {
469475
Some(('$', end2)) => {
470476
state = Prec;
471-
width = Some(Num::from_str("", Some(at.slice_between(end).unwrap())));
477+
width = Num::from_str("", at.slice_between(end));
472478
move_to!(end2);
473479
}
474480
_ => {
@@ -500,7 +506,7 @@ pub(crate) mod printf {
500506
match end.next_cp() {
501507
Some(('$', end2)) => {
502508
state = Length;
503-
precision = Some(Num::from_str("*", next.slice_between(end)));
509+
precision = Num::from_str("*", next.slice_between(end));
504510
move_to!(end2);
505511
}
506512
_ => {
@@ -513,7 +519,7 @@ pub(crate) mod printf {
513519
'0'..='9' => {
514520
let end = at_next_cp_while(next, char::is_ascii_digit);
515521
state = Length;
516-
precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
522+
precision = at.slice_between(end).and_then(|num| Num::from_str(num, None));
517523
move_to!(end);
518524
}
519525
_ => return fallback(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn main() {
2+
println!("%100000", 1);
3+
//~^ ERROR argument never used
4+
println!("% 65536", 1);
5+
//~^ ERROR argument never used
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: argument never used
2+
--> $DIR/println-percent-prefix-num-issue-125002.rs:2:25
3+
|
4+
LL | println!("%100000", 1);
5+
| ^ argument never used
6+
|
7+
note: format specifiers use curly braces, and the conversion specifier `1` is unknown or unsupported
8+
--> $DIR/println-percent-prefix-num-issue-125002.rs:2:15
9+
|
10+
LL | println!("%100000", 1);
11+
| ^^
12+
= note: printf formatting is not supported; see the documentation for `std::fmt`
13+
14+
error: argument never used
15+
--> $DIR/println-percent-prefix-num-issue-125002.rs:4:29
16+
|
17+
LL | println!("% 65536", 1);
18+
| ^ argument never used
19+
|
20+
note: format specifiers use curly braces, and the conversion specifier ` ` is unknown or unsupported
21+
--> $DIR/println-percent-prefix-num-issue-125002.rs:4:15
22+
|
23+
LL | println!("% 65536", 1);
24+
| ^^
25+
= note: printf formatting is not supported; see the documentation for `std::fmt`
26+
27+
error: aborting due to 2 previous errors
28+

0 commit comments

Comments
 (0)