Fix a panic when parsing var patterns
This commit is contained in:
committed by
Chris Fallin
parent
f2b6244b9c
commit
e3aeb850b2
13
cranelift/isle/Cargo.lock
generated
13
cranelift/isle/Cargo.lock
generated
@@ -115,6 +115,15 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.25.0"
|
||||
@@ -158,15 +167,17 @@ dependencies = [
|
||||
name = "isle-fuzz"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"env_logger 0.9.0",
|
||||
"isle",
|
||||
"libfuzzer-sys",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "islec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"env_logger 0.8.4",
|
||||
"isle",
|
||||
"log",
|
||||
"miette",
|
||||
|
||||
@@ -9,8 +9,10 @@ edition = "2018"
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
env_logger = { version = "0.9.0", default-features = false }
|
||||
isle = { path = "../isle" }
|
||||
libfuzzer-sys = "0.4"
|
||||
log = "0.4.14"
|
||||
|
||||
[[bin]]
|
||||
name = "parse"
|
||||
|
||||
@@ -3,8 +3,15 @@
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
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 _ = parser.parse_defs();
|
||||
|
||||
let defs = parser.parse_defs();
|
||||
log::debug!("defs = {:?}", defs);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -237,6 +237,7 @@ impl<'a> Lexer<'a> {
|
||||
let end = self.pos.offset;
|
||||
let s = std::str::from_utf8(&self.buf[start..end])
|
||||
.expect("Only ASCII characters, should be UTF-8");
|
||||
debug_assert!(!s.is_empty());
|
||||
Ok(Some((start_pos, Token::Symbol(s.to_string()))))
|
||||
}
|
||||
c if (c >= b'0' && c <= b'9') || c == b'-' => {
|
||||
|
||||
@@ -12,9 +12,6 @@ pub struct Parser<'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> {
|
||||
/// Construct a new parser from the given lexer.
|
||||
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 !f(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(|_| ())
|
||||
}
|
||||
fn rparen(&mut self) -> ParseResult<()> {
|
||||
fn rparen(&mut self) -> Result<()> {
|
||||
self.take(|tok| *tok == Token::RParen).map(|_| ())
|
||||
}
|
||||
fn at(&mut self) -> ParseResult<()> {
|
||||
fn at(&mut self) -> Result<()> {
|
||||
self.take(|tok| *tok == Token::At).map(|_| ())
|
||||
}
|
||||
fn lt(&mut self) -> ParseResult<()> {
|
||||
fn lt(&mut self) -> Result<()> {
|
||||
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())? {
|
||||
Token::Symbol(s) => Ok(s),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn int(&mut self) -> ParseResult<i64> {
|
||||
fn int(&mut self) -> Result<i64> {
|
||||
match self.take(|tok| tok.is_int())? {
|
||||
Token::Int(i) => Ok(i),
|
||||
_ => unreachable!(),
|
||||
@@ -117,7 +114,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// 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![];
|
||||
while !self.lexer.eof() {
|
||||
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()?;
|
||||
let pos = self.pos();
|
||||
let def = match &self.symbol()?[..] {
|
||||
@@ -146,8 +143,11 @@ impl<'a> Parser<'a> {
|
||||
Ok(def)
|
||||
}
|
||||
|
||||
fn str_to_ident(&self, pos: Pos, s: &str) -> ParseResult<Ident> {
|
||||
let first = s.chars().next().unwrap();
|
||||
fn str_to_ident(&self, pos: Pos, s: &str) -> Result<Ident> {
|
||||
let first = s
|
||||
.chars()
|
||||
.next()
|
||||
.ok_or_else(|| self.error(pos, "empty symbol".into()))?;
|
||||
if !first.is_alphabetic() && first != '_' && first != '$' {
|
||||
return Err(self.error(
|
||||
pos,
|
||||
@@ -169,13 +169,13 @@ impl<'a> Parser<'a> {
|
||||
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 s = self.symbol()?;
|
||||
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 ident = self.parse_ident()?;
|
||||
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 name = self.parse_ident()?;
|
||||
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();
|
||||
self.lparen()?;
|
||||
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() {
|
||||
let pos = self.pos();
|
||||
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();
|
||||
self.lparen()?;
|
||||
let name = self.parse_ident()?;
|
||||
@@ -259,7 +259,7 @@ impl<'a> Parser<'a> {
|
||||
Ok(Field { name, ty, pos })
|
||||
}
|
||||
|
||||
fn parse_decl(&mut self) -> ParseResult<Decl> {
|
||||
fn parse_decl(&mut self) -> Result<Decl> {
|
||||
let pos = self.pos();
|
||||
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();
|
||||
if self.is_sym_str("constructor") {
|
||||
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();
|
||||
self.lparen()?;
|
||||
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 prio = if self.is_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();
|
||||
if self.is_int() {
|
||||
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() {
|
||||
self.lt()?;
|
||||
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();
|
||||
if self.is_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();
|
||||
self.lparen()?;
|
||||
let var = self.parse_ident()?;
|
||||
|
||||
Reference in New Issue
Block a user