Skip to content

Commit d80f127

Browse files
committed
Avoid panic_bounds_check in fmt::write.
Writing any fmt::Arguments would trigger the inclusion of usize formatting and padding code in the resulting binary, because indexing used in fmt::write would generate code using panic_bounds_check, which prints the index and length. These bounds checks are not necessary, as fmt::Arguments never contains any out-of-bounds indexes. This change replaces them with unsafe get_unchecked, to reduce the amount of generated code, which is especially important for embedded targets.
1 parent ad268bd commit d80f127

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

library/core/src/fmt/mod.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,9 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
10821082
// a string piece.
10831083
for (arg, piece) in fmt.iter().zip(args.pieces.iter()) {
10841084
formatter.buf.write_str(*piece)?;
1085-
run(&mut formatter, arg, &args.args)?;
1085+
// SAFETY: arg and args.args come from the same Arguments,
1086+
// which guarantees the indexes are always within bounds.
1087+
unsafe { run(&mut formatter, arg, &args.args) }?;
10861088
idx += 1;
10871089
}
10881090
}
@@ -1096,25 +1098,36 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
10961098
Ok(())
10971099
}
10981100

1099-
fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result {
1101+
unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result {
11001102
fmt.fill = arg.format.fill;
11011103
fmt.align = arg.format.align;
11021104
fmt.flags = arg.format.flags;
1103-
fmt.width = getcount(args, &arg.format.width);
1104-
fmt.precision = getcount(args, &arg.format.precision);
1105+
// SAFETY: arg and args come from the same Arguments,
1106+
// which guarantees the indexes are always within bounds.
1107+
unsafe {
1108+
fmt.width = getcount(args, &arg.format.width);
1109+
fmt.precision = getcount(args, &arg.format.precision);
1110+
}
11051111

11061112
// Extract the correct argument
1107-
let value = args[arg.position];
1113+
1114+
// SAFETY: arg and args come from the same Arguments,
1115+
// which guarantees its index is always within bounds.
1116+
let value = unsafe { args.get_unchecked(arg.position) };
11081117

11091118
// Then actually do some printing
11101119
(value.formatter)(value.value, fmt)
11111120
}
11121121

1113-
fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option<usize> {
1122+
unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option<usize> {
11141123
match *cnt {
11151124
rt::v1::Count::Is(n) => Some(n),
11161125
rt::v1::Count::Implied => None,
1117-
rt::v1::Count::Param(i) => args[i].as_usize(),
1126+
rt::v1::Count::Param(i) => {
1127+
// SAFETY: cnt and args come from the same Arguments,
1128+
// which guarantees this index is always within bounds.
1129+
unsafe { args.get_unchecked(i).as_usize() }
1130+
}
11181131
}
11191132
}
11201133

0 commit comments

Comments
 (0)