From cb710f14aa2c04b5fbb332e56e766ad43afc409e Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 5 Jul 2024 12:19:55 +0800 Subject: [PATCH 1/2] Better parsing for break/return/throw. --- CHANGELOG.md | 6 ++++++ src/parser.rs | 47 +++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7721d53c1..ed1b7dd74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Rhai Release Notes Version 1.20.0 ============== +Enhancements +------------ + +* The `break`, `return` and `throw` statements can now be simply used as `switch` case statement expressions. Previously it is required that the statement be wrapped in a block. + + Version 1.19.0 ============== diff --git a/src/parser.rs b/src/parser.rs index 462b90057..22a7f984e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3328,18 +3328,18 @@ impl Engine { { let pos = eat_token(state.input, &Token::Break); - let expr = match state.input.peek().unwrap() { - // `break` at - (Token::EOF, ..) => None, - // `break` at end of block - (Token::RightBrace, ..) => None, - // `break;` - (Token::SemiColon, ..) => None, - // `break` with expression - _ => Some(self.parse_expr(state, settings.level_up()?)?.into()), - }; + let current_pos = state.input.peek().unwrap().1; - Ok(Stmt::BreakLoop(expr, ASTFlags::BREAK, pos)) + match self.parse_expr(state, settings.level_up()?) { + Ok(expr) => Ok(Stmt::BreakLoop(Some(expr.into()), ASTFlags::BREAK, pos)), + Err(err) => { + if state.input.peek().unwrap().1 == current_pos { + Ok(Stmt::BreakLoop(None, ASTFlags::BREAK, pos)) + } else { + return Err(err); + } + } + } } Token::Continue | Token::Break if self.allow_looping() => { Err(PERR::LoopBreak.into_err(token_pos)) @@ -3362,21 +3362,16 @@ impl Engine { }) .unwrap(); - match state.input.peek().unwrap() { - // `return`/`throw` at - (Token::EOF, ..) => Ok(Stmt::Return(None, return_type, token_pos)), - // `return`/`throw` at end of block - (Token::RightBrace, ..) - if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) => - { - Ok(Stmt::Return(None, return_type, token_pos)) - } - // `return;` or `throw;` - (Token::SemiColon, ..) => Ok(Stmt::Return(None, return_type, token_pos)), - // `return` or `throw` with expression - _ => { - let expr = self.parse_expr(state, settings.level_up()?)?; - Ok(Stmt::Return(Some(expr.into()), return_type, token_pos)) + let current_pos = state.input.peek().unwrap().1; + + match self.parse_expr(state, settings.level_up()?) { + Ok(expr) => Ok(Stmt::Return(Some(expr.into()), return_type, token_pos)), + Err(err) => { + if state.input.peek().unwrap().1 == current_pos { + Ok(Stmt::Return(None, return_type, token_pos)) + } else { + return Err(err); + } } } } From 60e76b537d0232eaed6a12d2084bb7a4070168de Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 13 Jul 2024 23:49:20 +0800 Subject: [PATCH 2/2] Fix bits iterator range bug. --- CHANGELOG.md | 5 +++++ src/packages/iter_basic.rs | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed1b7dd74..c4e59c686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Rhai Release Notes Version 1.20.0 ============== +Bug fixes +--------- + +* (Fuzzing) An integer-overflow bug from an inclusive range in the bits iterator is fixed. + Enhancements ------------ diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 8222c13ca..70f4e35d3 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -525,7 +525,14 @@ mod iterator_functions { pub fn bits_from_inclusive_range(value: INT, range: InclusiveRange) -> RhaiResultOf { let from = INT::max(*range.start(), 0); let to = INT::max(*range.end(), from - 1); - BitRange::new(value, from, to - from + 1) + + // It is OK to use `INT::MAX` as the length to avoid an addition overflow + // even though it is an off-by-one error because there cannot be so many bits anyway. + #[cfg(not(feature = "unchecked"))] + return BitRange::new(value, from, (to - from).checked_add(1).unwrap_or(INT::MAX)); + + #[cfg(feature = "unchecked")] + return BitRange::new(value, from, to - from + 1); } /// Return an iterator over a portion of bits in the number. ///