Skip to content

Commit ace2536

Browse files
authored
Merge pull request #1089 from epage/cap
perf(token): Don't allow unbounded backtrackable parsing
2 parents 773e4aa + bf98193 commit ace2536

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

crates/typos/src/tokens.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ mod parser {
141141
use winnow::stream::StreamIsPartial;
142142
use winnow::token::{one_of, take_while};
143143

144+
/// Avoid worst-case parse times by limiting how much a `take_while` can take if something
145+
/// later may cause it to fail.
146+
const NON_TERMINATING_CAP: usize = 1024;
147+
144148
pub(crate) fn next_identifier<T>(input: &mut T) -> PResult<<T as Stream>::Slice, ()>
145149
where
146150
T: Compare<char>,
@@ -446,7 +450,7 @@ mod parser {
446450
trace(
447451
"email",
448452
(
449-
take_while(1.., is_localport_char),
453+
take_while(1..NON_TERMINATING_CAP, is_localport_char),
450454
'@',
451455
take_while(1.., is_domain_char),
452456
)
@@ -466,15 +470,18 @@ mod parser {
466470
"url",
467471
(
468472
opt((
469-
take_while(1.., is_scheme_char),
473+
take_while(1..NON_TERMINATING_CAP, is_scheme_char),
470474
// HACK: Technically you can skip `//` if you don't have a domain but that would
471475
// get messy to support.
472476
(':', '/', '/'),
473477
)),
474478
(
475479
opt((url_userinfo, '@')),
476-
take_while(1.., is_domain_char),
477-
opt((':', take_while(1.., AsChar::is_dec_digit))),
480+
take_while(1..NON_TERMINATING_CAP, is_domain_char),
481+
opt((
482+
':',
483+
take_while(1..NON_TERMINATING_CAP, AsChar::is_dec_digit),
484+
)),
478485
),
479486
'/',
480487
// HACK: Too lazy to enumerate
@@ -495,8 +502,8 @@ mod parser {
495502
trace(
496503
"userinfo",
497504
(
498-
take_while(1.., is_localport_char),
499-
opt((':', take_while(0.., is_localport_char))),
505+
take_while(1..NON_TERMINATING_CAP, is_localport_char),
506+
opt((':', take_while(0..NON_TERMINATING_CAP, is_localport_char))),
500507
)
501508
.take(),
502509
)
@@ -515,7 +522,11 @@ mod parser {
515522
// incorrectly, we opt for just not evaluating it at all.
516523
trace(
517524
"escape",
518-
(take_while(1.., is_escape), take_while(0.., is_xid_continue)).take(),
525+
(
526+
take_while(1..NON_TERMINATING_CAP, is_escape),
527+
take_while(0.., is_xid_continue),
528+
)
529+
.take(),
519530
)
520531
.parse_next(input)
521532
}

0 commit comments

Comments
 (0)