mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-23 10:37:41 +08:00
stop panicking in case of internal error
This commit is contained in:
parent
3e5550c910
commit
7328ffb034
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user