-
-
Notifications
You must be signed in to change notification settings - Fork 6
Soundness Bug in this crate #166
Copy link
Copy link
Open
Description
Hi there!
We scanned the most popular libraries on crates.io and found some memory safety bugs in this library.
PoC
use std::fmt;
fn main() {
// Contains an escape char so we also exercise the escaping path,
// and invalid UTF-8 bytes to poison the unchecked &str slices.
let bytes: &[u8] = &[0xFF, b'&', 0xFF];
struct Trigger<'a>(&'a [u8]);
impl fmt::Display for Trigger<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// This is the crate's safe API that internally calls from_utf8_unchecked.
v_htmlescape::scalar::_escape(self.0, f)
}
}
// Get a String back from formatting.
let out = format!("{}", Trigger(bytes));
// Force UTF-8-dependent processing (should trip Miri if invalid UTF-8 got into a &str).
// Note: If the formatter happened to copy raw bytes, `out` could still be valid UTF-8;
// but if invalid `&str` was used, this will reliably diagnose.
let mut sum = 0usize;
for ch in out.chars() {
sum = sum.wrapping_add(ch as usize);
}
std::hint::black_box(sum);
}Miri Output
error: Undefined Behavior: constructing invalid value: encountered 0x001e686d, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
--> /home/ccuu/.rustup/toolchains/nightly-2025-10-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/char/methods.rs:239:18
|
239 | unsafe { super::convert::from_u32_unchecked(i) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `std::char::methods::<impl char>::from_u32_unchecked` at /home/ccuu/.rustup/toolchains/nightly-2025-10-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/char/methods.rs:239:18: 239:55
= note: inside closure at /home/ccuu/.rustup/toolchains/nightly-2025-10-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/str/iter.rs:42:59: 42:87
= note: inside `std::option::Option::<u32>::map::<char, {closure@<std::str::Chars<'_> as std::iter::Iterator>::next::{closure#0}}>` at /home/ccuu/.rustup/toolchains/nightly-2025-10-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1159:29: 1159:33
= note: inside `<std::str::Chars<'_> as std::iter::Iterator>::next` at /home/ccuu/.rustup/toolchains/nightly-2025-10-09-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/str/iter.rs:42:18: 42:88
note: inside `main`
--> src/main.rs:28:15
|
28 | for ch in out.chars() {
| ^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels