From 70178ff77a709df2f19a0233baf451b6163693e2 Mon Sep 17 00:00:00 2001 From: Tomas Tauber Date: Tue, 9 Aug 2022 21:48:48 +0800 Subject: [PATCH 1/6] fix: added a call limit setting to prevent crashes or timeouts closes #674, closes #675 --- meta/fuzz/Cargo.toml | 2 + meta/fuzz/fuzz_targets/parser.rs | 2 + meta/resources/test/fuzzsample1.grammar | 245 ++++++++++++++++++++++++ meta/resources/test/fuzzsample2.grammar | 6 + meta/resources/test/fuzzsample3.grammar | 102 ++++++++++ meta/src/parser.rs | 29 +++ pest/src/lib.rs | 4 +- pest/src/parser_state.rs | 149 ++++++++++++-- 8 files changed, 521 insertions(+), 18 deletions(-) create mode 100644 meta/resources/test/fuzzsample1.grammar create mode 100644 meta/resources/test/fuzzsample2.grammar create mode 100644 meta/resources/test/fuzzsample3.grammar diff --git a/meta/fuzz/Cargo.toml b/meta/fuzz/Cargo.toml index b2f074f9..7abfb152 100644 --- a/meta/fuzz/Cargo.toml +++ b/meta/fuzz/Cargo.toml @@ -8,6 +8,8 @@ rust-version = "1.56" [package.metadata] cargo-fuzz = true +[dependencies.pest] +path = "../../pest" [dependencies.pest_meta] path = ".." [dependencies.libfuzzer-sys] diff --git a/meta/fuzz/fuzz_targets/parser.rs b/meta/fuzz/fuzz_targets/parser.rs index 1e246c24..86f9d2bb 100644 --- a/meta/fuzz/fuzz_targets/parser.rs +++ b/meta/fuzz/fuzz_targets/parser.rs @@ -2,9 +2,11 @@ #[macro_use] extern crate libfuzzer_sys; extern crate pest_meta; +extern crate pest; fuzz_target!(|data: &[u8]| { if let Ok(s) = std::str::from_utf8(data) { + pest::set_call_limit(25_000, true); let _ = pest_meta::parser::parse(pest_meta::parser::Rule::grammar_rules, s); } }); diff --git a/meta/resources/test/fuzzsample1.grammar b/meta/resources/test/fuzzsample1.grammar new file mode 100644 index 00000000..c7adbcf0 --- /dev/null +++ b/meta/resources/test/fuzzsample1.grammar @@ -0,0 +1,245 @@ +w={ +(((((((((((((((((((((((((((((((( ((((((((((((((((((((( +((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( (((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( (((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( (((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( (((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( (((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( +((((( +((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( ((((((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((( +((((((((((((((((((((((((((((((//( (((((((((((((((((((((((((w={ +(( ((((((((((((((((((((((((((((( +((((( +((((((((((((((((((((((( ((((((((((((((((((((((((((((( +((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((( +((( (((((((((((((((((((((((( +((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( (((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((//( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((( (((((((((((((((((( ((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((( \ No newline at end of file diff --git a/meta/resources/test/fuzzsample2.grammar b/meta/resources/test/fuzzsample2.grammar new file mode 100644 index 00000000..f2f9f69b --- /dev/null +++ b/meta/resources/test/fuzzsample2.grammar @@ -0,0 +1,6 @@ + +/*//j/*/*;'//*//*/*/*;'/*//*/*;**//*//*/*/*;'/*/ /*//*/*/*;+/*//*/*;*B/*//*/*/*/*;'/*//*/*;**//*//*/*/*;'/*/ /*//*/*/*;+/*//*/*;*B/*//*//*/*;**N//*//*/*/*;'/*//*//*/ + +*//*/*;**N//*//*/*/*;'/*//*//*/ + +*/*;+/*//**/*/*;'/*//*//*;*/*///*/*; \ No newline at end of file diff --git a/meta/resources/test/fuzzsample3.grammar b/meta/resources/test/fuzzsample3.grammar new file mode 100644 index 00000000..02efa226 --- /dev/null +++ b/meta/resources/test/fuzzsample3.grammar @@ -0,0 +1,102 @@ +A=@{((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((PUSH(((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((PUSH((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((PUSH(((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( (((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( (((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((PUSH(((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((PUSH((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (((((((((((((((((((((((((((((((((((((PUSH(((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( (((((((((((((( (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( (((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( ((((((((((((((((((((( ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((! +(((((((((((((((((((((((((((((((((((((((((((((((((OOnOYYzOPUSH~OzOO)~OOOOz{1}{, + +3}{, + +1}{, + + +4}{ + +22, +6}{ + +22, + +2}{2, + + +3}{ + +2}{,4}{ +4}{ +22, + + +64444}{ +22, + + +6}{ + +0, +6}{ + +22, + +2}{2, + + +3}{ + +2}{,4}{ +23, + +(((((((((((((((((((((((((((((( + + + +? ((((((((( + + + + +f={"7MMg|g|&Hd_M \ No newline at end of file diff --git a/meta/src/parser.rs b/meta/src/parser.rs index 6526ef12..ecce7ae3 100644 --- a/meta/src/parser.rs +++ b/meta/src/parser.rs @@ -1501,4 +1501,33 @@ mod tests { assert_eq!(unescape(string), None); } + + #[test] + fn handles_deep_nesting() { + let sample1 = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/resources/test/fuzzsample1.grammar" + )); + let sample2 = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/resources/test/fuzzsample2.grammar" + )); + let sample3 = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/resources/test/fuzzsample3.grammar" + )); + const ERROR: &str = "call limit reached"; + pest::set_call_limit(3500, false); + let s1 = crate::parser::parse(crate::parser::Rule::grammar_rules, sample1); + assert!(s1.is_err()); + assert_eq!(s1.unwrap_err().variant.message(), ERROR); + pest::set_call_limit(25_000, true); + let s2 = crate::parser::parse(crate::parser::Rule::grammar_rules, sample2); + assert!(s2.is_err()); + assert_eq!(s2.unwrap_err().variant.message(), ERROR); + pest::set_call_limit(3500, false); + let s3 = crate::parser::parse(crate::parser::Rule::grammar_rules, sample3); + assert!(s3.is_err()); + assert_eq!(s3.unwrap_err().variant.message(), ERROR); + } } diff --git a/pest/src/lib.rs b/pest/src/lib.rs index d4a12e3d..30f87db6 100644 --- a/pest/src/lib.rs +++ b/pest/src/lib.rs @@ -75,7 +75,9 @@ extern crate serde; extern crate serde_json; pub use crate::parser::Parser; -pub use crate::parser_state::{state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState}; +pub use crate::parser_state::{ + set_call_limit, state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState, +}; pub use crate::position::Position; pub use crate::span::{Lines, LinesSpan, Span}; pub use crate::token::Token; diff --git a/pest/src/parser_state.rs b/pest/src/parser_state.rs index 934c10cc..32522f98 100644 --- a/pest/src/parser_state.rs +++ b/pest/src/parser_state.rs @@ -7,11 +7,13 @@ // option. All files in the project carrying such notice may not be copied, // modified, or distributed except according to those terms. +use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::rc::Rc; use alloc::vec; use alloc::vec::Vec; use core::ops::Range; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use crate::error::{Error, ErrorVariant}; use crate::iterators::{pairs, QueueableToken}; @@ -50,6 +52,63 @@ pub enum MatchDir { TopToBottom, } +static CALL_DEPTH_LIMIT: AtomicUsize = AtomicUsize::new(0); +static FINITE_CALL_LIMIT: AtomicBool = AtomicBool::new(false); + +/// Sets the maximum call limit for the parser +/// to prevent stack overflows or excessive execution times +/// in some grammars. +/// +/// # Arguments +/// +/// * `limit` - The maximum call depth or the number of calls. +/// If 0, the call depth or the number of calls is unlimited. +/// * `finite_calls` - If `true`, the parser execution is limited to +/// a finite number of calls (based on `limit`). +pub fn set_call_limit(limit: usize, finite_calls: bool) { + CALL_DEPTH_LIMIT.store(limit, Ordering::Relaxed); + FINITE_CALL_LIMIT.store(finite_calls, Ordering::Relaxed); +} + +#[derive(Debug)] +struct CallLimitTracker { + current_depth_limit: Option<(usize, usize)>, + finite_calls: bool, +} + +impl Default for CallLimitTracker { + fn default() -> Self { + let limit = CALL_DEPTH_LIMIT.load(Ordering::Relaxed); + let current_depth_limit = if limit > 0 { Some((0, limit)) } else { None }; + let finite_calls = FINITE_CALL_LIMIT.load(Ordering::Relaxed); + Self { + current_depth_limit, + finite_calls, + } + } +} + +impl CallLimitTracker { + fn limit_reached(&self) -> bool { + self.current_depth_limit + .map_or(false, |(current, limit)| current >= limit) + } + + fn increment_depth(&mut self) { + if let Some((current, limit)) = self.current_depth_limit { + self.current_depth_limit = Some((current.wrapping_add(1), limit)); + } + } + + fn decrement_depth(&mut self) { + if let Some((current, limit)) = self.current_depth_limit { + if !self.finite_calls { + self.current_depth_limit = Some((current.wrapping_sub(1), limit)); + } + } + } +} + /// The complete state of a [`Parser`]. /// /// [`Parser`]: trait.Parser.html @@ -63,6 +122,7 @@ pub struct ParserState<'i, R: RuleType> { attempt_pos: usize, atomicity: Atomicity, stack: Stack>, + call_tracker: CallLimitTracker, } /// Creates a `ParserState` from a `&str`, supplying it to a closure `f`. @@ -86,16 +146,23 @@ where Ok(pairs::new(Rc::new(state.queue), input, 0, len)) } Err(mut state) => { - state.pos_attempts.sort(); - state.pos_attempts.dedup(); - state.neg_attempts.sort(); - state.neg_attempts.dedup(); - - Err(Error::new_from_pos( + let variant = if state.reached_call_limit() { + ErrorVariant::CustomError { + message: "call limit reached".to_owned(), + } + } else { + state.pos_attempts.sort(); + state.pos_attempts.dedup(); + state.neg_attempts.sort(); + state.neg_attempts.dedup(); ErrorVariant::ParsingError { positives: state.pos_attempts.clone(), negatives: state.neg_attempts.clone(), - }, + } + }; + + Err(Error::new_from_pos( + variant, // TODO(performance): Guarantee state.attempt_pos is a valid position position::Position::new(input, state.attempt_pos).unwrap(), )) @@ -124,6 +191,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { attempt_pos: 0, atomicity: Atomicity::NonAtomic, stack: Stack::new(), + call_tracker: Default::default(), }) } @@ -170,6 +238,28 @@ impl<'i, R: RuleType> ParserState<'i, R> { self.atomicity } + #[inline] + fn inc_call_check_limit(mut self: Box) -> ParseResult> { + if self.call_tracker.limit_reached() { + self.queue.clear(); + return Err(self); + } + self.call_tracker.increment_depth(); + Ok(self) + } + + #[inline] + fn dec_call(&mut self) { + if !self.reached_call_limit() { + self.call_tracker.decrement_depth() + } + } + + #[inline] + fn reached_call_limit(&self) -> bool { + self.call_tracker.limit_reached() + } + /// Wrapper needed to generate tokens. This will associate the `R` type rule to the closure /// meant to match the rule. /// @@ -195,6 +285,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { where F: FnOnce(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; let actual_pos = self.position.pos(); let index = self.queue.len(); @@ -251,7 +342,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { input_pos: new_pos, }); } - + new_state.dec_call(); Ok(new_state) } Err(mut new_state) => { @@ -270,7 +361,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { { new_state.queue.truncate(index); } - + new_state.dec_call(); Err(new_state) } } @@ -359,21 +450,26 @@ impl<'i, R: RuleType> ParserState<'i, R> { /// assert_eq!(pairs.len(), 0); /// ``` #[inline] - pub fn sequence(self: Box, f: F) -> ParseResult> + pub fn sequence(mut self: Box, f: F) -> ParseResult> where F: FnOnce(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; let token_index = self.queue.len(); let initial_pos = self.position; let result = f(self); match result { - Ok(new_state) => Ok(new_state), + Ok(mut new_state) => { + new_state.dec_call(); + Ok(new_state) + } Err(mut new_state) => { // Restore the initial position and truncate the token queue. new_state.position = initial_pos; new_state.queue.truncate(token_index); + new_state.dec_call(); Err(new_state) } } @@ -408,16 +504,20 @@ impl<'i, R: RuleType> ParserState<'i, R> { /// assert_eq!(result.unwrap().position().pos(), 0); /// ``` #[inline] - pub fn repeat(self: Box, mut f: F) -> ParseResult> + pub fn repeat(mut self: Box, mut f: F) -> ParseResult> where F: FnMut(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; let mut result = f(self); loop { match result { Ok(state) => result = f(state), - Err(state) => return Ok(state), + Err(mut state) => { + state.dec_call(); + return Ok(state); + } }; } } @@ -449,12 +549,16 @@ impl<'i, R: RuleType> ParserState<'i, R> { /// assert!(result.is_ok()); /// ``` #[inline] - pub fn optional(self: Box, f: F) -> ParseResult> + pub fn optional(mut self: Box, f: F) -> ParseResult> where F: FnOnce(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; match f(self) { - Ok(state) | Err(state) => Ok(state), + Ok(mut state) | Err(mut state) => { + state.dec_call(); + Ok(state) + } } } @@ -730,6 +834,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { where F: FnOnce(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; let initial_lookahead = self.lookahead; self.lookahead = if is_positive { @@ -752,11 +857,13 @@ impl<'i, R: RuleType> ParserState<'i, R> { Ok(mut new_state) => { new_state.position = initial_pos; new_state.lookahead = initial_lookahead; + new_state.dec_call(); Ok(new_state.restore()) } Err(mut new_state) => { new_state.position = initial_pos; new_state.lookahead = initial_lookahead; + new_state.dec_call(); Err(new_state.restore()) } }; @@ -797,6 +904,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { where F: FnOnce(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; let initial_atomicity = self.atomicity; let should_toggle = self.atomicity != atomicity; @@ -808,12 +916,14 @@ impl<'i, R: RuleType> ParserState<'i, R> { match result { Ok(mut new_state) => { + new_state.dec_call(); if should_toggle { new_state.atomicity = initial_atomicity; } Ok(new_state) } Err(mut new_state) => { + new_state.dec_call(); if should_toggle { new_state.atomicity = initial_atomicity; } @@ -841,21 +951,26 @@ impl<'i, R: RuleType> ParserState<'i, R> { /// assert_eq!(result.unwrap().position().pos(), 1); /// ``` #[inline] - pub fn stack_push(self: Box, f: F) -> ParseResult> + pub fn stack_push(mut self: Box, f: F) -> ParseResult> where F: FnOnce(Box) -> ParseResult>, { + self = self.inc_call_check_limit()?; let start = self.position; let result = f(self); match result { Ok(mut state) => { + state.dec_call(); let end = state.position; state.stack.push(start.span(&end)); Ok(state) } - Err(state) => Err(state), + Err(mut state) => { + state.dec_call(); + Err(state) + } } } From 7a344211493a3585e671801f170ec0be380740e3 Mon Sep 17 00:00:00 2001 From: Tomas Tauber Date: Wed, 10 Aug 2022 18:02:45 +0800 Subject: [PATCH 2/6] simplified the set call to only keep track of finite calls --- meta/fuzz/fuzz_targets/parser.rs | 4 +- meta/src/parser.rs | 6 +-- pest/src/parser_state.rs | 71 +++++++------------------------- 3 files changed, 22 insertions(+), 59 deletions(-) diff --git a/meta/fuzz/fuzz_targets/parser.rs b/meta/fuzz/fuzz_targets/parser.rs index 86f9d2bb..f9b8cad6 100644 --- a/meta/fuzz/fuzz_targets/parser.rs +++ b/meta/fuzz/fuzz_targets/parser.rs @@ -4,9 +4,11 @@ extern crate libfuzzer_sys; extern crate pest_meta; extern crate pest; +use std::convert::TryInto; + fuzz_target!(|data: &[u8]| { if let Ok(s) = std::str::from_utf8(data) { - pest::set_call_limit(25_000, true); + pest::set_call_limit(Some(25_000usize.try_into().unwrap())); let _ = pest_meta::parser::parse(pest_meta::parser::Rule::grammar_rules, s); } }); diff --git a/meta/src/parser.rs b/meta/src/parser.rs index ecce7ae3..a5b2a078 100644 --- a/meta/src/parser.rs +++ b/meta/src/parser.rs @@ -621,6 +621,8 @@ fn unescape(string: &str) -> Option { #[cfg(test)] mod tests { + use std::convert::TryInto; + use super::super::unwrap_or_report; use super::*; @@ -1517,15 +1519,13 @@ mod tests { "/resources/test/fuzzsample3.grammar" )); const ERROR: &str = "call limit reached"; - pest::set_call_limit(3500, false); + pest::set_call_limit(Some(25_000usize.try_into().unwrap())); let s1 = crate::parser::parse(crate::parser::Rule::grammar_rules, sample1); assert!(s1.is_err()); assert_eq!(s1.unwrap_err().variant.message(), ERROR); - pest::set_call_limit(25_000, true); let s2 = crate::parser::parse(crate::parser::Rule::grammar_rules, sample2); assert!(s2.is_err()); assert_eq!(s2.unwrap_err().variant.message(), ERROR); - pest::set_call_limit(3500, false); let s3 = crate::parser::parse(crate::parser::Rule::grammar_rules, sample3); assert!(s3.is_err()); assert_eq!(s3.unwrap_err().variant.message(), ERROR); diff --git a/pest/src/parser_state.rs b/pest/src/parser_state.rs index 32522f98..15a826ed 100644 --- a/pest/src/parser_state.rs +++ b/pest/src/parser_state.rs @@ -12,8 +12,9 @@ use alloc::boxed::Box; use alloc::rc::Rc; use alloc::vec; use alloc::vec::Vec; +use core::num::NonZeroUsize; use core::ops::Range; -use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicUsize, Ordering}; use crate::error::{Error, ErrorVariant}; use crate::iterators::{pairs, QueueableToken}; @@ -52,8 +53,7 @@ pub enum MatchDir { TopToBottom, } -static CALL_DEPTH_LIMIT: AtomicUsize = AtomicUsize::new(0); -static FINITE_CALL_LIMIT: AtomicBool = AtomicBool::new(false); +static CALL_LIMIT: AtomicUsize = AtomicUsize::new(0); /// Sets the maximum call limit for the parser /// to prevent stack overflows or excessive execution times @@ -65,46 +65,32 @@ static FINITE_CALL_LIMIT: AtomicBool = AtomicBool::new(false); /// If 0, the call depth or the number of calls is unlimited. /// * `finite_calls` - If `true`, the parser execution is limited to /// a finite number of calls (based on `limit`). -pub fn set_call_limit(limit: usize, finite_calls: bool) { - CALL_DEPTH_LIMIT.store(limit, Ordering::Relaxed); - FINITE_CALL_LIMIT.store(finite_calls, Ordering::Relaxed); +pub fn set_call_limit(limit: Option) { + CALL_LIMIT.store(limit.map(|f| f.get()).unwrap_or(0), Ordering::Relaxed); } #[derive(Debug)] struct CallLimitTracker { - current_depth_limit: Option<(usize, usize)>, - finite_calls: bool, + current_call_limit: Option<(usize, usize)>, } impl Default for CallLimitTracker { fn default() -> Self { - let limit = CALL_DEPTH_LIMIT.load(Ordering::Relaxed); - let current_depth_limit = if limit > 0 { Some((0, limit)) } else { None }; - let finite_calls = FINITE_CALL_LIMIT.load(Ordering::Relaxed); - Self { - current_depth_limit, - finite_calls, - } + let limit = CALL_LIMIT.load(Ordering::Relaxed); + let current_call_limit = if limit > 0 { Some((0, limit)) } else { None }; + Self { current_call_limit } } } impl CallLimitTracker { fn limit_reached(&self) -> bool { - self.current_depth_limit + self.current_call_limit .map_or(false, |(current, limit)| current >= limit) } fn increment_depth(&mut self) { - if let Some((current, limit)) = self.current_depth_limit { - self.current_depth_limit = Some((current.wrapping_add(1), limit)); - } - } - - fn decrement_depth(&mut self) { - if let Some((current, limit)) = self.current_depth_limit { - if !self.finite_calls { - self.current_depth_limit = Some((current.wrapping_sub(1), limit)); - } + if let Some((current, limit)) = self.current_call_limit { + self.current_call_limit = Some((current.wrapping_add(1), limit)); } } } @@ -248,13 +234,6 @@ impl<'i, R: RuleType> ParserState<'i, R> { Ok(self) } - #[inline] - fn dec_call(&mut self) { - if !self.reached_call_limit() { - self.call_tracker.decrement_depth() - } - } - #[inline] fn reached_call_limit(&self) -> bool { self.call_tracker.limit_reached() @@ -342,7 +321,6 @@ impl<'i, R: RuleType> ParserState<'i, R> { input_pos: new_pos, }); } - new_state.dec_call(); Ok(new_state) } Err(mut new_state) => { @@ -361,7 +339,6 @@ impl<'i, R: RuleType> ParserState<'i, R> { { new_state.queue.truncate(index); } - new_state.dec_call(); Err(new_state) } } @@ -461,15 +438,11 @@ impl<'i, R: RuleType> ParserState<'i, R> { let result = f(self); match result { - Ok(mut new_state) => { - new_state.dec_call(); - Ok(new_state) - } + Ok(new_state) => Ok(new_state), Err(mut new_state) => { // Restore the initial position and truncate the token queue. new_state.position = initial_pos; new_state.queue.truncate(token_index); - new_state.dec_call(); Err(new_state) } } @@ -514,8 +487,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { loop { match result { Ok(state) => result = f(state), - Err(mut state) => { - state.dec_call(); + Err(state) => { return Ok(state); } }; @@ -555,10 +527,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { { self = self.inc_call_check_limit()?; match f(self) { - Ok(mut state) | Err(mut state) => { - state.dec_call(); - Ok(state) - } + Ok(state) | Err(state) => Ok(state), } } @@ -857,13 +826,11 @@ impl<'i, R: RuleType> ParserState<'i, R> { Ok(mut new_state) => { new_state.position = initial_pos; new_state.lookahead = initial_lookahead; - new_state.dec_call(); Ok(new_state.restore()) } Err(mut new_state) => { new_state.position = initial_pos; new_state.lookahead = initial_lookahead; - new_state.dec_call(); Err(new_state.restore()) } }; @@ -916,14 +883,12 @@ impl<'i, R: RuleType> ParserState<'i, R> { match result { Ok(mut new_state) => { - new_state.dec_call(); if should_toggle { new_state.atomicity = initial_atomicity; } Ok(new_state) } Err(mut new_state) => { - new_state.dec_call(); if should_toggle { new_state.atomicity = initial_atomicity; } @@ -962,15 +927,11 @@ impl<'i, R: RuleType> ParserState<'i, R> { match result { Ok(mut state) => { - state.dec_call(); let end = state.position; state.stack.push(start.span(&end)); Ok(state) } - Err(mut state) => { - state.dec_call(); - Err(state) - } + Err(state) => Err(state), } } From 64e421915ae0d8cc5b47d726164a83881f06daff Mon Sep 17 00:00:00 2001 From: Tomas Tauber Date: Wed, 10 Aug 2022 21:46:16 +0800 Subject: [PATCH 3/6] fix doc --- pest/src/parser_state.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pest/src/parser_state.rs b/pest/src/parser_state.rs index 15a826ed..f9af13d0 100644 --- a/pest/src/parser_state.rs +++ b/pest/src/parser_state.rs @@ -61,10 +61,8 @@ static CALL_LIMIT: AtomicUsize = AtomicUsize::new(0); /// /// # Arguments /// -/// * `limit` - The maximum call depth or the number of calls. -/// If 0, the call depth or the number of calls is unlimited. -/// * `finite_calls` - If `true`, the parser execution is limited to -/// a finite number of calls (based on `limit`). +/// * `limit` - The maximum number of calls. If None, +/// the number of calls is unlimited. pub fn set_call_limit(limit: Option) { CALL_LIMIT.store(limit.map(|f| f.get()).unwrap_or(0), Ordering::Relaxed); } From 707bd118d1b4d605809f1c69b8e3cfd0605413e9 Mon Sep 17 00:00:00 2001 From: Tomas Tauber Date: Wed, 10 Aug 2022 22:17:50 +0800 Subject: [PATCH 4/6] more explanation in the comment --- pest/src/parser_state.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pest/src/parser_state.rs b/pest/src/parser_state.rs index f9af13d0..d096f93d 100644 --- a/pest/src/parser_state.rs +++ b/pest/src/parser_state.rs @@ -55,9 +55,12 @@ pub enum MatchDir { static CALL_LIMIT: AtomicUsize = AtomicUsize::new(0); -/// Sets the maximum call limit for the parser +/// Sets the maximum call limit for the parser state /// to prevent stack overflows or excessive execution times /// in some grammars. +/// If set, the calls are tracked as a running total +/// over all non-terminal rules that can nest closures +/// (which are passed to transform the parser state). /// /// # Arguments /// From f9ff8f7cd9d2d9ecc2bcdb6f6774ab087207a57c Mon Sep 17 00:00:00 2001 From: Tomas Tauber Date: Wed, 10 Aug 2022 22:26:34 +0800 Subject: [PATCH 5/6] fmt nits --- pest/src/parser_state.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pest/src/parser_state.rs b/pest/src/parser_state.rs index d096f93d..62d22e5d 100644 --- a/pest/src/parser_state.rs +++ b/pest/src/parser_state.rs @@ -91,7 +91,7 @@ impl CallLimitTracker { fn increment_depth(&mut self) { if let Some((current, limit)) = self.current_call_limit { - self.current_call_limit = Some((current.wrapping_add(1), limit)); + self.current_call_limit = Some((current + 1, limit)); } } } @@ -322,6 +322,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { input_pos: new_pos, }); } + Ok(new_state) } Err(mut new_state) => { @@ -340,6 +341,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { { new_state.queue.truncate(index); } + Err(new_state) } } @@ -488,9 +490,7 @@ impl<'i, R: RuleType> ParserState<'i, R> { loop { match result { Ok(state) => result = f(state), - Err(state) => { - return Ok(state); - } + Err(state) => return Ok(state), }; } } From 953a782a4801e59a36377ac18ccd3debef12fb94 Mon Sep 17 00:00:00 2001 From: Tomas Tauber Date: Wed, 10 Aug 2022 23:25:11 +0800 Subject: [PATCH 6/6] increment fix --- pest/src/parser_state.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pest/src/parser_state.rs b/pest/src/parser_state.rs index 62d22e5d..76f0c26c 100644 --- a/pest/src/parser_state.rs +++ b/pest/src/parser_state.rs @@ -90,8 +90,8 @@ impl CallLimitTracker { } fn increment_depth(&mut self) { - if let Some((current, limit)) = self.current_call_limit { - self.current_call_limit = Some((current + 1, limit)); + if let Some((current, _)) = &mut self.current_call_limit { + *current += 1; } } }