Fix a panic when parsing var patterns

This commit is contained in:
Nick Fitzgerald
2021-09-28 16:27:59 -07:00
committed by Chris Fallin
parent f2b6244b9c
commit e3aeb850b2
5 changed files with 52 additions and 31 deletions

View File

@@ -115,6 +115,15 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"log",
]
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.25.0" version = "0.25.0"
@@ -158,15 +167,17 @@ dependencies = [
name = "isle-fuzz" name = "isle-fuzz"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"env_logger 0.9.0",
"isle", "isle",
"libfuzzer-sys", "libfuzzer-sys",
"log",
] ]
[[package]] [[package]]
name = "islec" name = "islec"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"env_logger", "env_logger 0.8.4",
"isle", "isle",
"log", "log",
"miette", "miette",

View File

@@ -9,8 +9,10 @@ edition = "2018"
cargo-fuzz = true cargo-fuzz = true
[dependencies] [dependencies]
env_logger = { version = "0.9.0", default-features = false }
isle = { path = "../isle" } isle = { path = "../isle" }
libfuzzer-sys = "0.4" libfuzzer-sys = "0.4"
log = "0.4.14"
[[bin]] [[bin]]
name = "parse" name = "parse"

View File

@@ -3,8 +3,15 @@
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
fuzz_target!(|s: &str| { fuzz_target!(|s: &str| {
if let Ok(lexer) = isle::lexer::Lexer::from_str(s, "fuzz-input.isle") { let _ = env_logger::try_init();
let lexer = isle::lexer::Lexer::from_str(s, "fuzz-input.isle");
log::debug!("lexer = {:?}", lexer);
if let Ok(lexer) = lexer {
let mut parser = isle::parser::Parser::new(lexer); let mut parser = isle::parser::Parser::new(lexer);
let _ = parser.parse_defs();
let defs = parser.parse_defs();
log::debug!("defs = {:?}", defs);
} }
}); });

View File

@@ -237,6 +237,7 @@ impl<'a> Lexer<'a> {
let end = self.pos.offset; let end = self.pos.offset;
let s = std::str::from_utf8(&self.buf[start..end]) let s = std::str::from_utf8(&self.buf[start..end])
.expect("Only ASCII characters, should be UTF-8"); .expect("Only ASCII characters, should be UTF-8");
debug_assert!(!s.is_empty());
Ok(Some((start_pos, Token::Symbol(s.to_string())))) Ok(Some((start_pos, Token::Symbol(s.to_string()))))
} }
c if (c >= b'0' && c <= b'9') || c == b'-' => { c if (c >= b'0' && c <= b'9') || c == b'-' => {

View File

@@ -12,9 +12,6 @@ pub struct Parser<'a> {
lexer: Lexer<'a>, lexer: Lexer<'a>,
} }
/// Either `Ok(T)` or an `Err(isle::Error)`.
pub type ParseResult<T> = std::result::Result<T, Error>;
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// Construct a new parser from the given lexer. /// Construct a new parser from the given lexer.
pub fn new(lexer: Lexer<'a>) -> Parser<'a> { pub fn new(lexer: Lexer<'a>) -> Parser<'a> {
@@ -32,7 +29,7 @@ impl<'a> Parser<'a> {
} }
} }
fn take<F: Fn(&Token) -> bool>(&mut self, f: F) -> ParseResult<Token> { fn take<F: Fn(&Token) -> bool>(&mut self, f: F) -> Result<Token> {
if let Some(&(pos, ref peek)) = self.lexer.peek() { if let Some(&(pos, ref peek)) = self.lexer.peek() {
if !f(peek) { if !f(peek) {
return Err(self.error(pos, format!("Unexpected token {:?}", peek))); return Err(self.error(pos, format!("Unexpected token {:?}", peek)));
@@ -89,27 +86,27 @@ impl<'a> Parser<'a> {
}) })
} }
fn lparen(&mut self) -> ParseResult<()> { fn lparen(&mut self) -> Result<()> {
self.take(|tok| *tok == Token::LParen).map(|_| ()) self.take(|tok| *tok == Token::LParen).map(|_| ())
} }
fn rparen(&mut self) -> ParseResult<()> { fn rparen(&mut self) -> Result<()> {
self.take(|tok| *tok == Token::RParen).map(|_| ()) self.take(|tok| *tok == Token::RParen).map(|_| ())
} }
fn at(&mut self) -> ParseResult<()> { fn at(&mut self) -> Result<()> {
self.take(|tok| *tok == Token::At).map(|_| ()) self.take(|tok| *tok == Token::At).map(|_| ())
} }
fn lt(&mut self) -> ParseResult<()> { fn lt(&mut self) -> Result<()> {
self.take(|tok| *tok == Token::Lt).map(|_| ()) self.take(|tok| *tok == Token::Lt).map(|_| ())
} }
fn symbol(&mut self) -> ParseResult<String> { fn symbol(&mut self) -> Result<String> {
match self.take(|tok| tok.is_sym())? { match self.take(|tok| tok.is_sym())? {
Token::Symbol(s) => Ok(s), Token::Symbol(s) => Ok(s),
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn int(&mut self) -> ParseResult<i64> { fn int(&mut self) -> Result<i64> {
match self.take(|tok| tok.is_int())? { match self.take(|tok| tok.is_int())? {
Token::Int(i) => Ok(i), Token::Int(i) => Ok(i),
_ => unreachable!(), _ => unreachable!(),
@@ -117,7 +114,7 @@ impl<'a> Parser<'a> {
} }
/// Parse the top-level ISLE definitions and return their AST. /// Parse the top-level ISLE definitions and return their AST.
pub fn parse_defs(&mut self) -> ParseResult<Defs> { pub fn parse_defs(&mut self) -> Result<Defs> {
let mut defs = vec![]; let mut defs = vec![];
while !self.lexer.eof() { while !self.lexer.eof() {
defs.push(self.parse_def()?); defs.push(self.parse_def()?);
@@ -129,7 +126,7 @@ impl<'a> Parser<'a> {
}) })
} }
fn parse_def(&mut self) -> ParseResult<Def> { fn parse_def(&mut self) -> Result<Def> {
self.lparen()?; self.lparen()?;
let pos = self.pos(); let pos = self.pos();
let def = match &self.symbol()?[..] { let def = match &self.symbol()?[..] {
@@ -146,8 +143,11 @@ impl<'a> Parser<'a> {
Ok(def) Ok(def)
} }
fn str_to_ident(&self, pos: Pos, s: &str) -> ParseResult<Ident> { fn str_to_ident(&self, pos: Pos, s: &str) -> Result<Ident> {
let first = s.chars().next().unwrap(); let first = s
.chars()
.next()
.ok_or_else(|| self.error(pos, "empty symbol".into()))?;
if !first.is_alphabetic() && first != '_' && first != '$' { if !first.is_alphabetic() && first != '_' && first != '$' {
return Err(self.error( return Err(self.error(
pos, pos,
@@ -169,13 +169,13 @@ impl<'a> Parser<'a> {
Ok(Ident(s.to_string(), pos)) Ok(Ident(s.to_string(), pos))
} }
fn parse_ident(&mut self) -> ParseResult<Ident> { fn parse_ident(&mut self) -> Result<Ident> {
let pos = self.pos(); let pos = self.pos();
let s = self.symbol()?; let s = self.symbol()?;
self.str_to_ident(pos, &s) self.str_to_ident(pos, &s)
} }
fn parse_const(&mut self) -> ParseResult<Ident> { fn parse_const(&mut self) -> Result<Ident> {
let pos = self.pos(); let pos = self.pos();
let ident = self.parse_ident()?; let ident = self.parse_ident()?;
if ident.0.starts_with("$") { if ident.0.starts_with("$") {
@@ -189,7 +189,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_type(&mut self) -> ParseResult<Type> { fn parse_type(&mut self) -> Result<Type> {
let pos = self.pos(); let pos = self.pos();
let name = self.parse_ident()?; let name = self.parse_ident()?;
let mut is_extern = false; let mut is_extern = false;
@@ -206,7 +206,7 @@ impl<'a> Parser<'a> {
}) })
} }
fn parse_typevalue(&mut self) -> ParseResult<TypeValue> { fn parse_typevalue(&mut self) -> Result<TypeValue> {
let pos = self.pos(); let pos = self.pos();
self.lparen()?; self.lparen()?;
if self.is_sym_str("primitive") { if self.is_sym_str("primitive") {
@@ -228,7 +228,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_type_variant(&mut self) -> ParseResult<Variant> { fn parse_type_variant(&mut self) -> Result<Variant> {
if self.is_sym() { if self.is_sym() {
let pos = self.pos(); let pos = self.pos();
let name = self.parse_ident()?; let name = self.parse_ident()?;
@@ -250,7 +250,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_type_field(&mut self) -> ParseResult<Field> { fn parse_type_field(&mut self) -> Result<Field> {
let pos = self.pos(); let pos = self.pos();
self.lparen()?; self.lparen()?;
let name = self.parse_ident()?; let name = self.parse_ident()?;
@@ -259,7 +259,7 @@ impl<'a> Parser<'a> {
Ok(Field { name, ty, pos }) Ok(Field { name, ty, pos })
} }
fn parse_decl(&mut self) -> ParseResult<Decl> { fn parse_decl(&mut self) -> Result<Decl> {
let pos = self.pos(); let pos = self.pos();
let term = self.parse_ident()?; let term = self.parse_ident()?;
@@ -280,7 +280,7 @@ impl<'a> Parser<'a> {
}) })
} }
fn parse_extern(&mut self) -> ParseResult<Extern> { fn parse_extern(&mut self) -> Result<Extern> {
let pos = self.pos(); let pos = self.pos();
if self.is_sym_str("constructor") { if self.is_sym_str("constructor") {
self.symbol()?; self.symbol()?;
@@ -341,7 +341,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_etor(&mut self) -> ParseResult<Extractor> { fn parse_etor(&mut self) -> Result<Extractor> {
let pos = self.pos(); let pos = self.pos();
self.lparen()?; self.lparen()?;
let term = self.parse_ident()?; let term = self.parse_ident()?;
@@ -359,7 +359,7 @@ impl<'a> Parser<'a> {
}) })
} }
fn parse_rule(&mut self) -> ParseResult<Rule> { fn parse_rule(&mut self) -> Result<Rule> {
let pos = self.pos(); let pos = self.pos();
let prio = if self.is_int() { let prio = if self.is_int() {
Some(self.int()?) Some(self.int()?)
@@ -376,7 +376,7 @@ impl<'a> Parser<'a> {
}) })
} }
fn parse_pattern(&mut self) -> ParseResult<Pattern> { fn parse_pattern(&mut self) -> Result<Pattern> {
let pos = self.pos(); let pos = self.pos();
if self.is_int() { if self.is_int() {
Ok(Pattern::ConstInt { Ok(Pattern::ConstInt {
@@ -433,7 +433,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_pattern_term_arg(&mut self) -> ParseResult<TermArgPattern> { fn parse_pattern_term_arg(&mut self) -> Result<TermArgPattern> {
if self.is_lt() { if self.is_lt() {
self.lt()?; self.lt()?;
Ok(TermArgPattern::Expr(self.parse_expr()?)) Ok(TermArgPattern::Expr(self.parse_expr()?))
@@ -442,7 +442,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_expr(&mut self) -> ParseResult<Expr> { fn parse_expr(&mut self) -> Result<Expr> {
let pos = self.pos(); let pos = self.pos();
if self.is_lparen() { if self.is_lparen() {
self.lparen()?; self.lparen()?;
@@ -487,7 +487,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse_letdef(&mut self) -> ParseResult<LetDef> { fn parse_letdef(&mut self) -> Result<LetDef> {
let pos = self.pos(); let pos = self.pos();
self.lparen()?; self.lparen()?;
let var = self.parse_ident()?; let var = self.parse_ident()?;