Skip to content

Commit

Permalink
Merge pull request #7430 from joshuawarner32/fuzzing-bugs-6
Browse files Browse the repository at this point in the history
Fix more fuzzing bugs
  • Loading branch information
smores56 authored Dec 30, 2024
2 parents 9000293 + 0e2f168 commit cb76268
Show file tree
Hide file tree
Showing 26 changed files with 144 additions and 120 deletions.
1 change: 1 addition & 0 deletions crates/compiler/fmt/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@ pub fn fmt_body<'a>(
&& !matches!(body.extract_spaces().item, Expr::Defs(..))
&& !matches!(body.extract_spaces().item, Expr::Return(..))
&& !matches!(body.extract_spaces().item, Expr::Backpassing(..))
&& !matches!(body.extract_spaces().item, Expr::DbgStmt { .. })
&& !starts_with_expect_ident(body)
} else {
false
Expand Down
6 changes: 4 additions & 2 deletions crates/compiler/parse/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EEx
positive_number_literal_help()
)),
loc(specialize_err(EExpr::Closure, closure_help(options))),
loc(crash_kw()),
loc(specialize_err(EExpr::Dbg, dbg_kw())),
loc(try_kw()),
loc(record_literal_help()),
Expand Down Expand Up @@ -284,12 +285,13 @@ fn underscore_expression<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
}

fn crash_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
(move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let (_, _, next_state) = crate::parser::keyword(crate::keyword::CRASH, EExpr::Crash)
.parse(arena, state, min_indent)?;

Ok((MadeProgress, Expr::Crash, next_state))
}
})
.trace("crash_kw")
}

fn loc_possibly_negative_or_negated_term<'a>(
Expand Down
15 changes: 7 additions & 8 deletions crates/compiler/parse/src/ident.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::ast::TryTarget;
use crate::keyword::is_allowed_identifier;
use crate::parser::Progress::{self, *};
use crate::parser::{BadInputError, EExpr, ParseResult, Parser};
use crate::state::State;
Expand Down Expand Up @@ -60,7 +61,7 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_lowercase_part(state.bytes()) {
Err(progress) => Err((progress, ())),
Ok(ident) => {
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
if !is_allowed_identifier(ident) {
Err((NoProgress, ()))
} else {
let width = ident.len();
Expand All @@ -87,7 +88,7 @@ pub fn lowercase_ident_keyword_e<'a>() -> impl Parser<'a, &'a str, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_lowercase_part(state.bytes()) {
Err(progress) => Err((progress, ())),
Ok(ident) => {
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
if !is_allowed_identifier(ident) {
Err((MadeProgress, ()))
} else {
let width = ident.len();
Expand Down Expand Up @@ -137,7 +138,7 @@ pub fn unqualified_ident<'a>() -> impl Parser<'a, &'a str, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_anycase_part(state.bytes()) {
Err(progress) => Err((progress, ())),
Ok(ident) => {
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
if !is_allowed_identifier(ident) {
Err((MadeProgress, ()))
} else {
let width = ident.len();
Expand Down Expand Up @@ -165,11 +166,9 @@ pub fn parse_ident<'a>(
let state = advance_state!(state, width as usize)?;
if let Ident::Access { module_name, parts } = ident {
if module_name.is_empty() {
if let Some(first) = parts.first() {
for keyword in crate::keyword::KEYWORDS.iter() {
if first == &Accessor::RecordField(keyword) {
return Err((NoProgress, EExpr::Start(initial.pos())));
}
if let Some(Accessor::RecordField(ident)) = parts.first() {
if !is_allowed_identifier(ident) {
return Err((NoProgress, EExpr::Start(initial.pos())));
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions crates/compiler/parse/src/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ pub const WHERE: &str = "where";
// These keywords are valid in headers
pub const PLATFORM: &str = "platform";

pub const KEYWORDS: [&str; 12] = [
pub const KEYWORDS: [&str; 11] = [
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, RETURN, CRASH,
"expect!", // not itself a keyword, but it's problematic if we allow an identifier like this!
];

pub fn is_allowed_identifier(mut ident: &str) -> bool {
if ident.ends_with('!') {
ident = &ident[..ident.len() - 1];
}
!crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw)
}
13 changes: 8 additions & 5 deletions crates/compiler/parse/src/type_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::parser::{
};
use crate::parser::{
allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes,
word, EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
Progress::*,
};
use crate::state::State;
Expand Down Expand Up @@ -322,7 +322,10 @@ fn loc_type_in_parens<'a>(
specialize_err_ref(ETypeInParens::Type, arrow()),
Sep::FunctionArrow
),
map(word(keyword::WHERE, ETypeInParens::End), |_| Sep::Where),
map(
crate::parser::keyword(keyword::WHERE, ETypeInParens::End),
|_| Sep::Where
),
];

match sep.parse(arena, state.clone(), 0) {
Expand Down Expand Up @@ -707,7 +710,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'
),
skip_first(
// Parse "implements"; we don't care about this keyword
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
crate::parser::keyword(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
// Parse "Hash & ..."; this may be qualified from another module like "Hash.Hash"
absolute_column_min_indent(ability_chain()),
),
Expand All @@ -734,7 +737,7 @@ fn implements_clause_chain<'a>(
move |arena, state: State<'a>, min_indent: u32| {
let (_, (spaces_before, ()), state) = and(
space0_e(EType::TIndentStart),
word(crate::keyword::WHERE, EType::TWhereBar),
crate::parser::keyword(crate::keyword::WHERE, EType::TWhereBar),
)
.parse(arena, state, min_indent)?;

Expand Down Expand Up @@ -768,7 +771,7 @@ fn parse_implements_clause_chain_after_where<'a>(
pub fn implements_abilities<'a>() -> impl Parser<'a, Loc<ImplementsAbilities<'a>>, EType<'a>> {
increment_min_indent(skip_first(
// Parse "implements"; we don't care about this keyword
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
crate::parser::keyword(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
// Parse "Hash"; this may be qualified from another module like "Hash.Hash"
space0_before_e(
loc(map(
Expand Down
4 changes: 2 additions & 2 deletions crates/compiler/test_syntax/src/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ impl<'a> Input<'a> {
* * * AST after formatting:\n{:#?}\n\n",
self.as_str(),
output.as_ref().as_str(),
ast_normalized,
reparsed_ast_normalized
actual,
reparsed_ast
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expr(Start(@0), @0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
D=return!-
e
z#
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expr(Start(@6), @0)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expr(BadExprEnd(@5), @0)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expr(BadExprEnd(@12), @0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
h-
-o -crash!
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expr(Type(TInParens(End(@5), @2), @2), @0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
s:(s
wherem
implementsF)A
_

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{} =
dbg c
c
e
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@0-15 SpaceAfter(
Defs(
Defs {
tags: [
EitherIndex(2147483648),
],
regions: [
@0-13,
],
space_before: [
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
],
space_after: [
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
],
spaces: [],
type_defs: [],
value_defs: [
Body(
@0-2 RecordDestructure(
[],
),
@5-10 SpaceBefore(
DbgStmt {
first: @9-10 Var {
module_name: "",
ident: "c",
},
extra_args: [],
continuation: @12-13 SpaceBefore(
Var {
module_name: "",
ident: "c",
},
[
Newline,
],
),
},
[
Newline,
],
),
),
],
},
@14-15 SpaceBefore(
Var {
module_name: "",
ident: "e",
},
[
Newline,
],
),
),
[
Newline,
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{}=
dbg c
c
e

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
(
i :
a #
where w implements I
i : a #
wherew implementsI
e
)
Loading

0 comments on commit cb76268

Please sign in to comment.