Description
I've been trying to find an error in my small application, hence decided to utilize AFL to try different inputs to it. Application is based on a library that uses regex under the hood.
So, with help of AFL I discovered that the application crashes in certain conditions.
In short, the following test fails:
#[test]
fn weird_thing1() {
// Note that 'Ј' is not 'j', but cyrillic Je
// https://en.wikipedia.org/wiki/Je_(Cyrillic)
let regx = "()Ј01";
let text = "()Ј01";
let replace_with = "w";
let re = regex::Regex::new(regx).unwrap();
assert_eq!(re.replace(text, replace_with), "()w");
}
- Expected: Probably
text
as is. Upd: or"()w"
- Actual: Panic:
thread 'replace::weird_thing1' panicked at 'BUG: reverse match implies forward match', src/exec.rs:889:27
Was able to reproduce only when parens and 'Je' symbol (https://en.wikipedia.org/wiki/Je_(Cyrillic)) are present, and followed by two or more characters.
See playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=53d71f4fa917ddba17d19630b86a81ac
One more weird thing:
I decided to add simple tests to tests/replace.rs
to try it out, but faced the following:
-
When only one test is added, like
replace!(weird_thing1, replace, r"()Ј01", "()Ј01", t!("w"), "()w");
test case fails with (
$ cargo test replace
)... test replace::trim ... ok test replace::weird_thing1 ... FAILED failures: ---- replace::weird_thing1 stdout ---- thread 'replace::weird_thing1' panicked at 'BUG: reverse match implies forward match', src/exec.rs:889:27 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: replace::weird_thing1 test result: FAILED. 18 passed; 1 failed; 0 ignored; 0 measured; 780 filtered out
-
But when I add another one like
replace!(weird_thing1, replace, r"()Ј01", "()Ј01", t!("w"), "()w"); // the first one replace!(weird_thing2, replace, r"()Ј01", "()Ј01", t!("w"), "something"); // a new one
then (
$ cargo test replace
)test replace::trim ... ok test replace::weird_thing1 ... ok test replace::weird_thing2 ... FAILED failures: ---- replace::weird_thing2 stdout ---- thread 'replace::weird_thing2' panicked at 'assertion failed: `(left == right)` left: `"()w"`, right: `"something"`', tests/replace.rs:13:1 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: replace::weird_thing2 test result: FAILED. 19 passed; 1 failed; 0 ignored; 0 measured; 769 filtered out
Which basically means that the first test finished successfully, and the second one reached the assert!
statement. On the playground, I haven't tried the regex!()
macro which is used in tests/replace.rs
. So it could be the reason why this behavior is not the same on the playground, where Regex::new()
is used.