Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 42ca58d

Browse files
committed
Throw, if BlockSyntax.parseLines loops indefinitely
We throw an `AssertionError` if `BlockSyntax.parseLines` enters an infinite loop. This should have no effect, if there are no bugs. But if there is a bug, it's easier to discover it in production if the failure mode isn't an infinite loop eating up CPU, but just an unhandled exception.
1 parent 86ebc2c commit 42ca58d

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

lib/src/block_parser.dart

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ class BlockParser {
164164
// number of cells, which makes a table like structure not be recognized.
165165
BlockSyntax? neverMatch;
166166

167+
var iterationsWithoutProgress = 0;
167168
while (!isDone) {
169+
final positionBefore = _pos;
168170
for (final syntax in blockSyntaxes) {
169171
if (neverMatch == syntax) {
170172
continue;
@@ -173,7 +175,6 @@ class BlockParser {
173175
if (syntax.canParse(this)) {
174176
_previousSyntax = _currentSyntax;
175177
_currentSyntax = syntax;
176-
final positionBefore = _pos;
177178
final block = syntax.parse(this);
178179
if (block != null) {
179180
blocks.add(block);
@@ -189,6 +190,25 @@ class BlockParser {
189190
break;
190191
}
191192
}
193+
// Count the number of iterations without progress.
194+
// This ensures that we don't have an infinite loop. And if we have an
195+
// infinite loop, it's easier to gracefully recover from an error, than
196+
// it is to discover an kill an isolate that's stuck in an infinite loop.
197+
// Technically, it should be perfectly safe to remove this check
198+
// But as it's possible to inject custom BlockSyntax implementations and
199+
// combine existing ones, it is hard to promise that no combination can't
200+
// trigger an infinite loop
201+
if (positionBefore == _pos) {
202+
iterationsWithoutProgress++;
203+
if (iterationsWithoutProgress > 2) {
204+
// If this happens we throw an error to avoid having the parser
205+
// running in an infinite loop. An error is easier to handle.
206+
// If you see this error in production please file a bug!
207+
throw AssertionError('BlockParser.parseLines is not advancing');
208+
}
209+
} else {
210+
iterationsWithoutProgress = 0;
211+
}
192212
}
193213

194214
return blocks;

0 commit comments

Comments
 (0)