• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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