mirror of
				https://github.com/meilisearch/meilisearch.git
				synced 2025-10-31 16:06:31 +00:00 
			
		
		
		
	stop panicking in case of internal error
This commit is contained in:
		| @@ -1,13 +1,18 @@ | ||||
| #![no_main] | ||||
| use filter_parser::FilterCondition; | ||||
| use filter_parser::{ErrorKind, FilterCondition}; | ||||
| use libfuzzer_sys::fuzz_target; | ||||
|  | ||||
| fuzz_target!(|data: &[u8]| { | ||||
|     if let Ok(s) = std::str::from_utf8(data) { | ||||
|         // When we are fuzzing the parser we can get stack overflow really easily. | ||||
|         // When we are fuzzing the parser we can get a stack overflow very easily. | ||||
|         // But since this doesn't happens with a normal build we are just going to limit the fuzzer to 500 characters. | ||||
|         if s.len() < 500 { | ||||
|             let _ = FilterCondition::parse(s); | ||||
|             match FilterCondition::parse(s) { | ||||
|                 Err(e) if matches!(e.kind(), ErrorKind::InternalError(_)) => { | ||||
|                     panic!("Found an internal error: `{:?}`", e) | ||||
|                 } | ||||
|                 _ => (), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|   | ||||
| @@ -63,9 +63,14 @@ pub enum ErrorKind<'a> { | ||||
| } | ||||
|  | ||||
| impl<'a> Error<'a> { | ||||
|     pub fn kind(context: Span<'a>, kind: ErrorKind<'a>) -> Self { | ||||
|     pub fn kind(&self) -> &ErrorKind<'a> { | ||||
|         &self.kind | ||||
|     } | ||||
|  | ||||
|     pub fn new_from_kind(context: Span<'a>, kind: ErrorKind<'a>) -> Self { | ||||
|         Self { context, kind } | ||||
|     } | ||||
|  | ||||
|     pub fn char(self) -> char { | ||||
|         match self.kind { | ||||
|             ErrorKind::Char(c) => c, | ||||
|   | ||||
| @@ -162,12 +162,12 @@ fn parse_geo_radius(input: Span) -> IResult<FilterCondition> { | ||||
|         // if we were able to parse `_geoRadius` and can't parse the rest of the input we returns a failure | ||||
|         cut(delimited(char('('), separated_list1(tag(","), ws(|c| recognize_float(c))), char(')'))), | ||||
|     )(input) | ||||
|     .map_err(|e| e.map(|_| Error::kind(input, ErrorKind::Geo))); | ||||
|     .map_err(|e| e.map(|_| Error::new_from_kind(input, ErrorKind::Geo))); | ||||
|  | ||||
|     let (input, args) = parsed?; | ||||
|  | ||||
|     if args.len() != 3 { | ||||
|         return Err(nom::Err::Failure(Error::kind(input, ErrorKind::Geo))); | ||||
|         return Err(nom::Err::Failure(Error::new_from_kind(input, ErrorKind::Geo))); | ||||
|     } | ||||
|  | ||||
|     let res = FilterCondition::GeoLowerThan { | ||||
| @@ -186,9 +186,9 @@ fn parse_geo_point(input: Span) -> IResult<FilterCondition> { | ||||
|         // if we were able to parse `_geoPoint` we are going to return a Failure whatever happens next. | ||||
|         cut(delimited(char('('), separated_list1(tag(","), ws(|c| recognize_float(c))), char(')'))), | ||||
|     ))(input) | ||||
|     .map_err(|e| e.map(|_| Error::kind(input, ErrorKind::ReservedGeo("_geoPoint"))))?; | ||||
|     .map_err(|e| e.map(|_| Error::new_from_kind(input, ErrorKind::ReservedGeo("_geoPoint"))))?; | ||||
|     // if we succeeded we still returns a Failure because geoPoints are not allowed | ||||
|     Err(nom::Err::Failure(Error::kind(input, ErrorKind::ReservedGeo("_geoPoint")))) | ||||
|     Err(nom::Err::Failure(Error::new_from_kind(input, ErrorKind::ReservedGeo("_geoPoint")))) | ||||
| } | ||||
|  | ||||
| /// primary        = (WS* ~ "("  expression ")" ~ WS*) | geoRadius | condition | to | ||||
| @@ -199,7 +199,7 @@ fn parse_primary(input: Span) -> IResult<FilterCondition> { | ||||
|             ws(char('(')), | ||||
|             cut(parse_expression), | ||||
|             cut_with_err(ws(char(')')), |c| { | ||||
|                 Error::kind(input, ErrorKind::MissingClosingDelimiter(c.char())) | ||||
|                 Error::new_from_kind(input, ErrorKind::MissingClosingDelimiter(c.char())) | ||||
|             }), | ||||
|         ), | ||||
|         |c| parse_geo_radius(c), | ||||
| @@ -209,7 +209,7 @@ fn parse_primary(input: Span) -> IResult<FilterCondition> { | ||||
|         |c| parse_geo_point(c), | ||||
|     ))(input) | ||||
|     // if the inner parsers did not match enough information to return an accurate error | ||||
|     .map_err(|e| e.map_err(|_| Error::kind(input, ErrorKind::InvalidPrimary))) | ||||
|     .map_err(|e| e.map_err(|_| Error::new_from_kind(input, ErrorKind::InvalidPrimary))) | ||||
| } | ||||
|  | ||||
| /// expression     = or | ||||
|   | ||||
| @@ -15,11 +15,11 @@ pub fn parse_value(input: Span) -> IResult<Token> { | ||||
|         return Err(err); | ||||
|     } | ||||
|     match parse_geo_radius(input) { | ||||
|         Ok(_) => return Err(nom::Err::Failure(Error::kind(input, ErrorKind::MisusedGeo))), | ||||
|         Ok(_) => return Err(nom::Err::Failure(Error::new_from_kind(input, ErrorKind::MisusedGeo))), | ||||
|         // if we encountered a failure it means the user badly wrote a _geoRadius filter. | ||||
|         // But instead of showing him how to fix his syntax we are going to tell him he should not use this filter as a value. | ||||
|         Err(e) if e.is_failure() => { | ||||
|             return Err(nom::Err::Failure(Error::kind(input, ErrorKind::MisusedGeo))) | ||||
|             return Err(nom::Err::Failure(Error::new_from_kind(input, ErrorKind::MisusedGeo))) | ||||
|         } | ||||
|         _ => (), | ||||
|     } | ||||
| @@ -45,9 +45,11 @@ pub fn parse_value(input: Span) -> IResult<Token> { | ||||
|     )(input) | ||||
|     .map(|(s, t)| (s, t.into())) | ||||
|     // if we found nothing in the alt it means the user did not input any value | ||||
|     .map_err(|e| e.map_err(|_| Error::kind(input, ErrorKind::ExpectedValue))) | ||||
|     .map_err(|e| e.map_err(|_| Error::new_from_kind(input, ErrorKind::ExpectedValue))) | ||||
|     // if we found encountered a failure it means the user really tried to input a value, but had an unmatched quote | ||||
|     .map_err(|e| e.map_fail(|c| Error::kind(input, ErrorKind::MissingClosingDelimiter(c.char())))) | ||||
|     .map_err(|e| { | ||||
|         e.map_fail(|c| Error::new_from_kind(input, ErrorKind::MissingClosingDelimiter(c.char()))) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| fn is_key_component(c: char) -> bool { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user