1 #![no_main]
2 use libfuzzer_sys::fuzz_target;
3 use std::str;
4
5 extern crate nom;
6
7 use nom::{
8 branch::alt,
9 bytes::complete::tag,
10 character::complete::char,
11 character::complete::{digit1 as digit, space0 as space},
12 combinator::{map, map_res, verify},
13 multi::fold_many0,
14 sequence::{delimited, pair, terminated},
15 IResult,
16 };
17
18 use std::str::FromStr;
19 use std::cell::RefCell;
20
21 thread_local! {
22 pub static LEVEL: RefCell<u32> = RefCell::new(0);
23 }
24
reset()25 fn reset() {
26 LEVEL.with(|l| {
27 *l.borrow_mut() = 0;
28 });
29 }
30
incr(i: &str) -> IResult<&str, ()>31 fn incr(i: &str) -> IResult<&str, ()> {
32 LEVEL.with(|l| {
33 *l.borrow_mut() += 1;
34
35 // limit the number of recursions, the fuzzer keeps running into them
36 if *l.borrow() >= 8192 {
37 return Err(nom::Err::Failure(nom::error::Error::new(i, nom::error::ErrorKind::Count)));
38 } else {
39 Ok((i, ()))
40 }
41 })
42 }
43
decr()44 fn decr() {
45 LEVEL.with(|l| {
46 *l.borrow_mut() -= 1;
47 });
48 }
49
parens(i: &str) -> IResult<&str, i64>50 fn parens(i: &str) -> IResult<&str, i64> {
51 delimited(space, delimited(
52 terminated(tag("("), incr),
53 expr,
54 map(tag(")"), |_| decr())
55 ), space)(i)
56 }
57
58
factor(i: &str) -> IResult<&str, i64>59 fn factor(i: &str) -> IResult<&str, i64> {
60 alt((
61 map_res(delimited(space, digit, space), FromStr::from_str),
62 parens,
63 ))(i)
64 }
65
66
term(i: &str) -> IResult<&str, i64>67 fn term(i: &str) -> IResult<&str, i64> {
68 incr(i)?;
69 let (i, init) = factor(i).map_err(|e| { decr(); e })?;
70
71 let res = fold_many0(
72 alt((
73 pair(char('*'), factor),
74 pair(char('/'), verify(factor, |i| *i != 0)),
75 )),
76 || init,
77 |acc, (op, val): (char, i64)| {
78 if op == '*' {
79 acc.saturating_mul(val)
80 } else {
81 match acc.checked_div(val) {
82 Some(v) => v,
83 // we get a division with overflow because we can get acc = i64::MIN and val = -1
84 // the division by zero is already checked earlier by verify
85 None => i64::MAX,
86 }
87 }
88 },
89 )(i);
90
91 decr();
92 res
93 }
94
expr(i: &str) -> IResult<&str, i64>95 fn expr(i: &str) -> IResult<&str, i64> {
96 incr(i)?;
97 let (i, init) = term(i).map_err(|e| { decr(); e })?;
98
99 let res = fold_many0(
100 pair(alt((char('+'), char('-'))), term),
101 || init,
102 |acc, (op, val): (char, i64)| {
103 if op == '+' {
104 acc.saturating_add(val)
105 } else {
106 acc.saturating_sub(val)
107 }
108 },
109 )(i);
110
111 decr();
112 res
113 }
114
115 fuzz_target!(|data: &[u8]| {
116 reset();
117 // fuzzed code goes here
118 let temp = match str::from_utf8(data) {
119 Ok(v) => {
120 //println!("v: {}", v);
121 factor(v)
122 },
123 Err(e) => factor("2"),
124 };
125 });
126