From 6205132ba01efeda6171d6f64aae0e7274145a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=8D=E7=A0=8D?= Date: Fri, 14 Mar 2025 13:33:32 +0800 Subject: [PATCH 1/3] Enable Max Depth for Tokenizer to Avoid Crash --- Sources/Splash/Tokenizing/Tokenizer.swift | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Sources/Splash/Tokenizing/Tokenizer.swift b/Sources/Splash/Tokenizing/Tokenizer.swift index 2431504..8aeedc5 100644 --- a/Sources/Splash/Tokenizing/Tokenizer.swift +++ b/Sources/Splash/Tokenizing/Tokenizer.swift @@ -25,8 +25,8 @@ private extension Tokenizer { } mutating func next() -> Segment? { - var segment = nextSegment ?? iterator.next() - nextSegment = iterator.next() + var segment = nextSegment ?? iterator.controlledIterate(depth: 32) + nextSegment = iterator.controlledIterate(depth: 32) segment?.tokens.next = nextSegment?.tokens.current return segment } @@ -60,6 +60,12 @@ private extension Tokenizer { } mutating func next() -> Segment? { + controlledIterate(depth: 32) + } + + mutating func controlledIterate(depth: Int) -> Segment? { + guard depth >= 0 else { return nil } + let nextIndex = makeNextIndex() guard nextIndex != code.endIndex else { @@ -75,11 +81,12 @@ private extension Tokenizer { case .token, .delimiter: guard var segment = segments.current else { segments.current = makeSegment(with: component, at: nextIndex) - return next() + return controlledIterate(depth: depth - 1) } guard segment.trailingWhitespace == nil, - component.isDelimiter == segment.currentTokenIsDelimiter else { + component.isDelimiter == segment.currentTokenIsDelimiter + else { return finish(segment, with: component, at: nextIndex) } @@ -95,14 +102,14 @@ private extension Tokenizer { segment.tokens.current.append(component.character) segments.current = segment - return next() + return controlledIterate(depth: depth - 1) case .whitespace, .newline: guard var segment = segments.current else { var segment = makeSegment(with: component, at: nextIndex) segment.trailingWhitespace = component.token segment.isLastOnLine = component.isNewline segments.current = segment - return next() + return controlledIterate(depth: depth - 1) } if var existingWhitespace = segment.trailingWhitespace { @@ -117,7 +124,7 @@ private extension Tokenizer { } segments.current = segment - return next() + return controlledIterate(depth: depth - 1) } } From 4d997712fe07f75695aacdf287aeb3b1f2c6ab88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=8D=E7=A0=8D?= Date: Sat, 15 Mar 2025 22:49:51 +0800 Subject: [PATCH 2/3] Create StackOverflowTests.swift --- .../Tests/StackOverflowTests.swift | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Tests/SplashTests/Tests/StackOverflowTests.swift diff --git a/Tests/SplashTests/Tests/StackOverflowTests.swift b/Tests/SplashTests/Tests/StackOverflowTests.swift new file mode 100644 index 0000000..264d664 --- /dev/null +++ b/Tests/SplashTests/Tests/StackOverflowTests.swift @@ -0,0 +1,20 @@ +// +// StackOverflowTests.swift +// Splash +// +// Created by 秋星桥 on 3/15/25. +// + +import Foundation +import Splash +import XCTest + +final class StackOverflowTests: SyntaxHighlighterTestCase { + func testStackOverflow() { + _ = highlighter.highlight(testDocument) + } +} + +private let testDocument = """ +U1LDE3LjU1LDAsMSwwLTM1LjwwLDEPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMjMzLjQ1LDQwLjgxYTE3LjtMzUuMSwwVjMzMGExMS42MywxMS42MywwLDEsMC0yMy4yNiwwdjQwLjg2YTQwLjgxLDQwLjgxLDAsMCwwLDgxLjYyNTUsMTcuNTUsMCwwLDEtMzUuMSwwVjMzMGExMS42MywxMS42MywwLDEsMC0yMy4yNiwwdjQwLjg2YTQwLjgxLDQwLjgxLDAsMCwwLDgxLjYyLDBWNDAuODFjE1LjksNjMuNEE0MC44Niw0MC44NiwwLDAsMCw0aIi8hdGggY2xhc3M9ImNscy0xIiBkPSJNMjMzLjQ1LDQwLjgxYTE3LjU1LDE3LjU1LDAsMSwwLTM1LjEsMFYzMzEuNTZhNDAuODIsNDAuODIsMCwwLDEtODEuNjMsMFYxNDVhMTcuNTUsMTcu40MmExMS42MywxMS42MywwLDAsMSwyMy4yNiwwdjI4LjY2YTE3LjU1LDE3LjU1LDAsMCwwLDM1LjEsMFYxNDVBNDAuODIsNDAuODIsMCwwLDEsMTQwLDE0NVYzMzEuNTZhMTsMFYyODEuNTZhMTEuNjMsMTEuNjMsMCwxLDEtMjMuMjYsMFptMjE1LjksNjMuNEE0MC44Niw0MC44NiwwLDAsMCw0MDguNTMsMTQ1VjMwMC44NWExNy41NSwxNy41NSwwLDAsMS0zNS4wMDguNTMsMTQ1VjMwMC44NWExNy41NSwxNy41NSwwLDAsMS0zNS4wOSwwdi0yNjBhNDAuODIsNDAuODIsMCwwLDAtODEuNjMsMFYzNzAuODlhMTcuLjg1LDQwMCwxLDAtMzUuMDksMHY3ExLjYzLDExLjYzLDAsMCwwLDIzLjI2LDBWMTQ1QTQwLjg1LDQwLjg1LDAsMCwwLDQ0OS4zNSwxMDQuMjFaIi8NmE0MC44Miw0MC44MiwwLDAsMS04MS42MywwVjMFYxNDVBNDAuODIsNDAuODIsMCwwLDEsMTQwLDE0NVYzMzEuNTZhMTcuNTUsMTcuNTUsMCwwLDAsMzUuMSwwVjIxNy41aDBWNDAuODFhNDAuODEsNDAuODEsMCwxLDEsODEuNjAsMhMTcuNTUsMTcuNTUsMCwwLNTUsQTQwLDBWNDAuODFhMTcuNTUsMTcuNTUsMCwwLDEsMzUuMSwwdjI2MGE0MC44Miw0MC44MiwwLDAsMCw4MS42MywwVjE0NWExNy41NSwxNy41NSwwLDEsMSwzNS4xLDBWMjgxLjU2YTQuMjFOSwwdi0yNjBhNDAuODIsNDAEsMFYzMzEuNTZhNDAuODIsNDAuODIsMCwwLDEtODEuNjMsMFYxNDVhMTcuNTUsMTcuNTUsMCwxLDAtMzUuMDksMHY3OS4wPHBuODIsMCE5NSDEsMzUuMSwwdjI2MGE0MC44Miw0MC44MiwwLDAsMCw4MS42MywwVjE0NWExNy41NSwxNy41NSwwLDEsMSwzNS4xLDBWMjgxLjU2YTExLjYzLDExLjYzLDAsMCwwLDIzLjI2LDBWMTQ1Ljg1LDcuNTUsMTcuNTUsMCwwLDAsMzUuMSwwVjIxNy41aDBWNDAuODFhNDAuODEsNDAuODEsMCwxLDEsODEuNjIsMFYyODEuNTZhMTEuNjMsMTEuNjMsMCwxLDEtMjMuMjYsMFptMCwwLDQ0OS4zNSwxMDOS4wNmE0MC44Miw0MC44MiwwLDAsMS04MS42MywwVjE5NS40MmExMS42MywxMS42MywwLDAsMSwyMy4yNiwwdjI4LjY2YTE3LjU1LDE3LjU1LDAsMCwwLDM1LjEswwLDAtODEuNjMsMFYzNzAuODlhMTcuNTUsMTcuNTUsMC +""" From de9cde249fdb7a173a6e6b950ab18b11f6c2a557 Mon Sep 17 00:00:00 2001 From: Lakr Date: Wed, 9 Jul 2025 16:51:19 +0800 Subject: [PATCH 3/3] Update AttributedStringOutputFormat.swift --- .../Output/AttributedStringOutputFormat.swift | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Sources/Splash/Output/AttributedStringOutputFormat.swift b/Sources/Splash/Output/AttributedStringOutputFormat.swift index 4a54733..f6adf8e 100644 --- a/Sources/Splash/Output/AttributedStringOutputFormat.swift +++ b/Sources/Splash/Output/AttributedStringOutputFormat.swift @@ -34,8 +34,12 @@ public extension AttributedStringOutputFormat { } public mutating func addToken(_ token: String, ofType type: TokenType) { - let color = theme.tokenColors[type] ?? Color(red: 1, green: 1, blue: 1) - string.append(token, font: font, color: color) + if #available(iOS 13.0, macCatalyst 13.0, *) { + let color = theme.tokenColors[type] ?? Color.label + string.append(token, font: font, color: color) + } else { + string.append(token, font: font, color: Color(red: 1, green: 1, blue: 1)) + } } public mutating func addPlainText(_ text: String) { @@ -43,8 +47,13 @@ public extension AttributedStringOutputFormat { } public mutating func addWhitespace(_ whitespace: String) { - let color = Color(red: 1, green: 1, blue: 1) - string.append(whitespace, font: font, color: color) + if #available(iOS 13.0, macCatalyst 13.0, *) { + let color = Color.label + string.append(whitespace, font: font, color: color) + } else { + let color = Color(red: 1, green: 1, blue: 1) + string.append(whitespace, font: font, color: color) + } } public func build() -> NSAttributedString {