Skip to content

Commit

Permalink
Throw, if BlockSyntax.parseLines loops indefinitely (#533)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jonasfj authored Apr 20, 2023
1 parent 86ebc2c commit 5f98aea
Showing 1 changed file with 21 additions and 1 deletion.
22 changes: 21 additions & 1 deletion lib/src/block_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ class BlockParser {
// number of cells, which makes a table like structure not be recognized.
BlockSyntax? neverMatch;

var iterationsWithoutProgress = 0;
while (!isDone) {
final positionBefore = _pos;
for (final syntax in blockSyntaxes) {
if (neverMatch == syntax) {
continue;
Expand All @@ -173,7 +175,6 @@ class BlockParser {
if (syntax.canParse(this)) {
_previousSyntax = _currentSyntax;
_currentSyntax = syntax;
final positionBefore = _pos;
final block = syntax.parse(this);
if (block != null) {
blocks.add(block);
Expand All @@ -189,6 +190,25 @@ class BlockParser {
break;
}
}
// Count the number of iterations without progress.
// This ensures that we don't have an infinite loop. And if we have an
// infinite loop, it's easier to gracefully recover from an error, than
// it is to discover an kill an isolate that's stuck in an infinite loop.
// Technically, it should be perfectly safe to remove this check
// But as it's possible to inject custom BlockSyntax implementations and
// combine existing ones, it is hard to promise that no combination can't
// trigger an infinite loop
if (positionBefore == _pos) {
iterationsWithoutProgress++;
if (iterationsWithoutProgress > 2) {
// If this happens we throw an error to avoid having the parser
// running in an infinite loop. An error is easier to handle.
// If you see this error in production please file a bug!
throw AssertionError('BlockParser.parseLines is not advancing');
}
} else {
iterationsWithoutProgress = 0;
}
}

return blocks;
Expand Down

0 comments on commit 5f98aea

Please sign in to comment.