Skip to content

Commit d033375

Browse files
committed
expr: Fix error message for too big range quantifier index
1 parent 6aeae43 commit d033375

File tree

3 files changed

+78
-30
lines changed

3 files changed

+78
-30
lines changed

src/uu/expr/src/expr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ pub enum ExprError {
5050
InvalidBracketContent,
5151
#[error("Trailing backslash")]
5252
TrailingBackslash,
53+
#[error("Regular expression too big")]
54+
TooBigRangeQuantifierIndex,
5355
}
5456

5557
impl UError for ExprError {

src/uu/expr/src/syntax_tree.rs

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,15 @@ impl StringOp {
192192
let _ = re_string.pop();
193193
}
194194
re_string.push(curr);
195-
} else if is_valid_range_quantifier(&pattern_chars) {
195+
} else {
196+
// Check if the following section is a valid range quantifier
197+
verify_range_quantifier(&pattern_chars)?;
198+
196199
re_string.push(curr);
197200
// Set the lower bound of range quantifier to 0 if it is missing
198201
if pattern_chars.peek() == Some(&',') {
199202
re_string.push('0');
200203
}
201-
} else {
202-
return Err(ExprError::InvalidBracketContent);
203204
}
204205
}
205206
_ => re_string.push(curr),
@@ -222,7 +223,7 @@ impl StringOp {
222223
// "invalid repeat range {lower,upper}"
223224
-123 => ExprError::InvalidBracketContent,
224225
// "too big number for repeat range"
225-
-201 => ExprError::InvalidBracketContent,
226+
-201 => ExprError::TooBigRangeQuantifierIndex,
226227
_ => ExprError::InvalidRegexExpression,
227228
})?;
228229

@@ -277,23 +278,27 @@ where
277278
/// - `r"\{,6\}"`
278279
/// - `r"\{3,6\}"`
279280
/// - `r"\{,\}"`
280-
fn is_valid_range_quantifier<I>(pattern_chars: &I) -> bool
281+
fn verify_range_quantifier<I>(pattern_chars: &I) -> Result<(), ExprError>
281282
where
282283
I: Iterator<Item = char> + Clone,
283284
{
284285
// Parse the string between braces
285286
let mut quantifier = String::new();
286287
let mut pattern_chars_clone = pattern_chars.clone().peekable();
287288
let Some(mut prev) = pattern_chars_clone.next() else {
288-
return false;
289+
return Err(ExprError::UnmatchedOpeningBrace);
289290
};
291+
if pattern_chars_clone.peek().is_none() {
292+
return Err(ExprError::UnmatchedOpeningBrace);
293+
}
294+
290295
let mut prev_is_escaped = false;
291296
while let Some(curr) = pattern_chars_clone.next() {
292297
if prev == '\\' && curr == '}' && !prev_is_escaped {
293298
break;
294299
}
295300
if pattern_chars_clone.peek().is_none() {
296-
return false;
301+
return Err(ExprError::UnmatchedOpeningBrace);
297302
}
298303

299304
quantifier.push(prev);
@@ -302,19 +307,32 @@ where
302307
}
303308

304309
// Check if parsed quantifier is valid
305-
let is_valid_range_index = |s: &str| s.parse::<i32>().map_or(true, |x| x <= i16::MAX as i32);
306310
let re = Regex::new(r"^(\d*,\d*|\d+)").expect("valid regular expression");
307311
if let Some(captures) = re.captures(&quantifier) {
308312
let matched = captures.at(0).unwrap_or_default();
309313
match matched.split_once(',') {
310-
None => is_valid_range_index(matched),
311-
Some(("", "")) => true,
312-
Some((x, "")) => is_valid_range_index(x),
313-
Some(("", x)) => is_valid_range_index(x),
314-
Some((f, l)) => f <= l && is_valid_range_index(f) && is_valid_range_index(l),
314+
Some(("", "")) => Ok(()),
315+
Some((x, "")) | Some(("", x)) => match x.parse::<i32>() {
316+
Ok(x) if x <= i16::MAX.into() => Ok(()),
317+
Ok(_) => Err(ExprError::TooBigRangeQuantifierIndex),
318+
Err(_) => Err(ExprError::InvalidBracketContent),
319+
},
320+
Some((f, l)) => match (f.parse::<i32>(), l.parse::<i32>()) {
321+
(Ok(f), Ok(l)) if f > l => Err(ExprError::InvalidBracketContent),
322+
(Ok(f), Ok(l)) if f > i16::MAX.into() || l > i16::MAX.into() => {
323+
Err(ExprError::TooBigRangeQuantifierIndex)
324+
}
325+
(Ok(_), Ok(_)) => Ok(()),
326+
_ => Err(ExprError::InvalidBracketContent),
327+
},
328+
None => match matched.parse::<i32>() {
329+
Ok(x) if x <= i16::MAX.into() => Ok(()),
330+
Ok(_) => Err(ExprError::TooBigRangeQuantifierIndex),
331+
Err(_) => Err(ExprError::InvalidBracketContent),
332+
},
315333
}
316334
} else {
317-
false
335+
Err(ExprError::InvalidBracketContent)
318336
}
319337
}
320338

@@ -789,7 +807,7 @@ pub fn is_truthy(s: &NumOrStr) -> bool {
789807
#[cfg(test)]
790808
mod test {
791809
use crate::ExprError;
792-
use crate::syntax_tree::is_valid_range_quantifier;
810+
use crate::syntax_tree::verify_range_quantifier;
793811

794812
use super::{
795813
AstNode, AstNodeInner, BinOp, NumericOp, RelationOp, StringOp, check_posix_regex_errors,
@@ -999,19 +1017,47 @@ mod test {
9991017

10001018
#[test]
10011019
fn test_is_valid_range_quantifier() {
1002-
assert!(is_valid_range_quantifier(&"3\\}".chars()));
1003-
assert!(is_valid_range_quantifier(&"3,\\}".chars()));
1004-
assert!(is_valid_range_quantifier(&",6\\}".chars()));
1005-
assert!(is_valid_range_quantifier(&"3,6\\}".chars()));
1006-
assert!(is_valid_range_quantifier(&",\\}".chars()));
1007-
assert!(is_valid_range_quantifier(&"3,6\\}anything".chars()));
1008-
assert!(!is_valid_range_quantifier(&"\\{3,6\\}".chars()));
1009-
assert!(!is_valid_range_quantifier(&"\\}".chars()));
1010-
assert!(!is_valid_range_quantifier(&"".chars()));
1011-
assert!(!is_valid_range_quantifier(&"3".chars()));
1012-
assert!(!is_valid_range_quantifier(&"3,".chars()));
1013-
assert!(!is_valid_range_quantifier(&",6".chars()));
1014-
assert!(!is_valid_range_quantifier(&"3,6".chars()));
1015-
assert!(!is_valid_range_quantifier(&",".chars()));
1020+
assert!(verify_range_quantifier(&"3\\}".chars()).is_ok());
1021+
assert!(verify_range_quantifier(&"3,\\}".chars()).is_ok());
1022+
assert!(verify_range_quantifier(&",6\\}".chars()).is_ok());
1023+
assert!(verify_range_quantifier(&"3,6\\}".chars()).is_ok());
1024+
assert!(verify_range_quantifier(&",\\}".chars()).is_ok());
1025+
assert!(verify_range_quantifier(&"32767\\}anything".chars()).is_ok());
1026+
assert_eq!(
1027+
verify_range_quantifier(&"\\{3,6\\}".chars()),
1028+
Err(ExprError::InvalidBracketContent)
1029+
);
1030+
assert_eq!(
1031+
verify_range_quantifier(&"\\}".chars()),
1032+
Err(ExprError::InvalidBracketContent)
1033+
);
1034+
assert_eq!(
1035+
verify_range_quantifier(&"".chars()),
1036+
Err(ExprError::UnmatchedOpeningBrace)
1037+
);
1038+
assert_eq!(
1039+
verify_range_quantifier(&"3".chars()),
1040+
Err(ExprError::UnmatchedOpeningBrace)
1041+
);
1042+
assert_eq!(
1043+
verify_range_quantifier(&"3,".chars()),
1044+
Err(ExprError::UnmatchedOpeningBrace)
1045+
);
1046+
assert_eq!(
1047+
verify_range_quantifier(&",6".chars()),
1048+
Err(ExprError::UnmatchedOpeningBrace)
1049+
);
1050+
assert_eq!(
1051+
verify_range_quantifier(&"3,6".chars()),
1052+
Err(ExprError::UnmatchedOpeningBrace)
1053+
);
1054+
assert_eq!(
1055+
verify_range_quantifier(&",".chars()),
1056+
Err(ExprError::UnmatchedOpeningBrace)
1057+
);
1058+
assert_eq!(
1059+
verify_range_quantifier(&"32768\\}".chars()),
1060+
Err(ExprError::TooBigRangeQuantifierIndex)
1061+
);
10161062
}
10171063
}

tests/by-util/test_expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ mod gnu_expr {
12101210
.args(&["_", ":", "a\\{32768\\}"])
12111211
.fails_with_code(2)
12121212
.no_stdout()
1213-
.stderr_contains("Invalid content of \\{\\}");
1213+
.stderr_contains("expr: Regular expression too big\n");
12141214
}
12151215

12161216
#[test]

0 commit comments

Comments
 (0)