Skip to content

fix: prevent infinite loop in SrtParse on non-numeric trailing content - #933

Merged
kingslay merged 1 commit into
kingslay:mainfrom
YuriNachos:fix/srtparse-infinite-loop
Aug 11, 2026
Merged

kingslay merged 1 commit into
kingslay:mainfrom
YuriNachos:fix/srtparse-infinite-loop

Conversation

@YuriNachos

Copy link
Copy Markdown
Contributor

Problem

SrtParse.parsePart can hang forever (infinite loop) while parsing SRT input whose trailing content is not a numeric cue index. Reproduces with any of:

  • a stray non-numeric line after the last cue (e.g. a truncated download, a BOM/separator line, a tool signature);
  • trailing whitespace-only lines;
  • an SRT-shaped file that contains --> (so canParse accepts it) but never yields a numeric sequence line.

Once this happens the whole subtitle parser never returns.

Root cause

The sequence-number scan in SrtParse.parsePart has no end-of-input guard:

repeat {
    decimal = scanner.scanUpToCharacters(from: .newlines)
    _ = scanner.scanCharacters(from: .newlines)
} while decimal.flatMap(Int.init) == nil

When the scanner is parked on a non-numeric line at end of input, scanUpToCharacters(from: .newlines) returns nil (the current character is already a newline / EOF) and scanCharacters(from: .newlines) returns nil (nothing left to consume). Neither call advances the position, and decimal.flatMap(Int.init) stays nil, so the loop spins forever.

The sibling VTT parser already defends against this — VTTParse.parsePart terminates its timestamp-scan loop with && !scanner.isAtEnd; SRT was simply missing the same guard.

Fix

Add && !scanner.isAtEnd to the loop condition (one line). After the loop, scanner.scanUpToString("-->") returns nil at EOF, the existing if let startString, let endString = … check fails, parsePart returns nil, and the outer while !scanner.isAtEnd loop in parse(scanner:) exits cleanly.

Verification

  • swift build for macOS: clean.
  • swift test --filter SubtitleTest: passes (3 cases), including the new testSrtTrailingJunkDoesNotHang and the existing testSrt (still 9 cues, parts[8].end == 3601.14 — no regression).
  • Without the guard the new test never returns (the loop hangs), which is exactly the bug.

SrtParse.parsePart's sequence-number scan looped while looking for the
integer cue index, with no end-of-input guard. Once the scanner reaches a
non-numeric line at end of input (a trailing junk line, trailing
whitespace, or a truncated cue), neither scanUpToCharacters nor
scanCharacters advances the position nor yields an Int, so the loop spins
forever and hangs the whole subtitle parser.

Add an isAtEnd guard to the loop condition, mirroring the guard
VTTParse.parsePart already has on its own timestamp-scan loop. After the
loop, the existing startString nil-check returns nil, so the outer parse
loop exits cleanly.

Includes a regression test (testSrtTrailingJunkDoesNotHang) that parses an
SRT whose trailing content is not a numeric sequence line and asserts the
single valid cue is returned; without the guard the test never returns.
@kingslay
kingslay merged commit 019fbd8 into kingslay:main Aug 11, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants