Skip to content

Commit e455ddb

Browse files
committed
Avoid infinite loops in many0! and many1!
Fix for #27
1 parent cce29cd commit e455ddb

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## [Unreleased][unreleased]
44

55
### Changed
6+
- `many0!` and `many1!` forbid parsers that do not consume input
7+
- `is_a!`, `is_not!`, `alpha`, `digit`, `space`, `multispace` will now return an error if they do not consume at least one byte
68

79
## 0.2.1 - 2015-04-04
810

src/macros.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,11 @@ macro_rules! is_not(
433433
}
434434
if parsed { break; }
435435
}
436-
IResult::Done(&$input[index..], &$input[0..index])
436+
if index == 0 {
437+
IResult::Error(0)
438+
} else {
439+
IResult::Done(&$input[index..], &$input[0..index])
440+
}
437441
}
438442
);
439443
);
@@ -473,7 +477,11 @@ macro_rules! is_a(
473477
}
474478
if !cont { break; }
475479
}
476-
IResult::Done(&$input[index..], &$input[0..index])
480+
if index == 0 {
481+
IResult::Error(0)
482+
} else {
483+
IResult::Done(&$input[index..], &$input[0..index])
484+
}
477485
}
478486
);
479487
);
@@ -500,7 +508,11 @@ macro_rules! filter(
500508
break;
501509
}
502510
}
503-
IResult::Done(&$input[index..], &$input[0..index])
511+
if index == 0 {
512+
IResult::Error(0)
513+
} else {
514+
IResult::Done(&$input[index..], &$input[0..index])
515+
}
504516
}
505517
);
506518
);
@@ -605,6 +617,9 @@ macro_rules! many0(
605617
loop {
606618
match $submac!(&$i[begin..], $($args)*) {
607619
IResult::Done(i,o) => {
620+
if i.len() == $i[begin..].len() {
621+
break;
622+
}
608623
res.push(o);
609624
begin += remaining - i.len();
610625
remaining = i.len();
@@ -622,7 +637,7 @@ macro_rules! many0(
622637
);
623638
);
624639

625-
/// Applies the parser 0 or more times and returns the list of results in a Vec
640+
/// Applies the parser 1 or more times and returns the list of results in a Vec
626641
///
627642
/// the embedded parser may return Incomplete
628643
///
@@ -646,6 +661,9 @@ macro_rules! many1(
646661
loop {
647662
match $submac!(&$i[begin..], $($args)*) {
648663
IResult::Done(i,o) => {
664+
if i.len() == $i[begin..].len() {
665+
break;
666+
}
649667
res.push(o);
650668
begin += remaining - i.len();
651669
remaining = i.len();
@@ -655,7 +673,7 @@ macro_rules! many1(
655673
}
656674
}
657675
}
658-
if begin == 0 {
676+
if res.len() == 0 {
659677
IResult::Error(0)
660678
} else {
661679
IResult::Done(&$i[begin..], res)
@@ -1012,7 +1030,7 @@ mod tests {
10121030
assert_eq!(a_or_b(b), Done(&b"cde"[..], &b"b"[..]));
10131031

10141032
let c = &b"cdef"[..];
1015-
assert_eq!(a_or_b(c), Done(&b"cdef"[..], &b""[..]));
1033+
assert_eq!(a_or_b(c), Error(0));
10161034

10171035
let d = &b"bacdef"[..];
10181036
assert_eq!(a_or_b(d), Done(&b"cdef"[..], &b"ba"[..]));
@@ -1186,6 +1204,22 @@ mod tests {
11861204
assert_eq!(multi(c), Error(0));
11871205
}
11881206

1207+
#[test]
1208+
fn infinite_many() {
1209+
fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> {
1210+
Error(0)
1211+
}
1212+
1213+
// should not go into an infinite loop
1214+
named!(multi0<&[u8],Vec<&[u8]> >, many0!(tst));
1215+
let a = &b"abcdef"[..];
1216+
assert_eq!(multi0(a), Done(a, Vec::new()));
1217+
1218+
named!(multi1<&[u8],Vec<&[u8]> >, many1!(tst));
1219+
let a = &b"abcdef"[..];
1220+
assert_eq!(multi1(a), Error(0));
1221+
}
1222+
11891223
#[test]
11901224
fn take_until_test() {
11911225
named!(x, take_until_and_consume!("efgh"));

src/nom.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ pub fn is_space(chr:u8) -> bool {
7575
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
7676
for idx in 0..input.len() {
7777
if !is_alphabetic(input[idx]) {
78-
return Done(&input[idx..], &input[0..idx])
78+
if idx == 0 {
79+
return Error(0)
80+
} else {
81+
return Done(&input[idx..], &input[0..idx])
82+
}
7983
}
8084
}
8185
Done(b"", input)
@@ -84,7 +88,11 @@ pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
8488
pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
8589
for idx in 0..input.len() {
8690
if !is_digit(input[idx]) {
87-
return Done(&input[idx..], &input[0..idx])
91+
if idx == 0 {
92+
return Error(0)
93+
} else {
94+
return Done(&input[idx..], &input[0..idx])
95+
}
8896
}
8997
}
9098
Done(b"", input)
@@ -93,7 +101,11 @@ pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
93101
pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
94102
for idx in 0..input.len() {
95103
if !is_alphanumeric(input[idx]) {
96-
return Done(&input[idx..], &input[0..idx])
104+
if idx == 0 {
105+
return Error(0)
106+
} else {
107+
return Done(&input[idx..], &input[0..idx])
108+
}
97109
}
98110
}
99111
Done(b"", input)
@@ -102,16 +114,25 @@ pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
102114
pub fn space(input:&[u8]) -> IResult<&[u8], &[u8]> {
103115
for idx in 0..input.len() {
104116
if !is_space(input[idx]) {
105-
return Done(&input[idx..], &input[0..idx])
117+
if idx == 0 {
118+
return Error(0)
119+
} else {
120+
return Done(&input[idx..], &input[0..idx])
121+
}
106122
}
107123
}
108124
Done(b"", input)
109125
}
110126

111127
pub fn multispace(input:&[u8]) -> IResult<&[u8], &[u8]> {
112128
for idx in 0..input.len() {
129+
println!("multispace at index: {}", idx);
113130
if !is_space(input[idx]) && input[idx] != '\r' as u8 && input[idx] != '\n' as u8 {
114-
return Done(&input[idx..], &input[0..idx])
131+
if idx == 0 {
132+
return Error(0)
133+
} else {
134+
return Done(&input[idx..], &input[0..idx])
135+
}
115136
}
116137
}
117138
Done(b"", input)
@@ -267,13 +288,13 @@ mod tests {
267288
let d: &[u8] = "azé12".as_bytes();
268289
let e: &[u8] = b" ";
269290
assert_eq!(alpha(a), Done(empty, a));
270-
assert_eq!(alpha(b), Done(b, empty));
291+
assert_eq!(alpha(b), Error(0));
271292
assert_eq!(alpha(c), Done(&c[1..], &b"a"[..]));
272293
assert_eq!(alpha(d), Done("é12".as_bytes(), &b"az"[..]));
273-
assert_eq!(digit(a), Done(a, empty));
294+
assert_eq!(digit(a), Error(0));
274295
assert_eq!(digit(b), Done(empty, b));
275-
assert_eq!(digit(c), Done(c, empty));
276-
assert_eq!(digit(d), Done(d, empty));
296+
assert_eq!(digit(c), Error(0));
297+
assert_eq!(digit(d), Error(0));
277298
assert_eq!(alphanumeric(a), Done(empty, a));
278299
assert_eq!(alphanumeric(b), Done(empty, b));
279300
assert_eq!(alphanumeric(c), Done(empty, c));

0 commit comments

Comments
 (0)