Skip to content

Commit

Permalink
ISSUE-#1064 Prevent crash caused by TOMLKit Parsing error
Browse files Browse the repository at this point in the history
- Prevents TOMLKit table header parsing error from crashing AeroSpace by
doing a pre-check for invalid table headers.

- Additionally throws a helpful user error showing the line number +
content of the invalid config line
  • Loading branch information
fullmetalsheep committed Feb 24, 2025
1 parent f6876d2 commit f9b82da
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion Sources/AppBundle/config/parseConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AppKit
import Common
import HotKey
import TOMLKit
import Foundation

func readConfig(forceConfigUrl: URL? = nil) -> Result<(Config, URL), String> {
let customConfigUrl: URL
Expand Down Expand Up @@ -30,7 +31,7 @@ func readConfig(forceConfigUrl: URL? = nil) -> Result<(Config, URL), String> {
}
}

enum TomlParseError: Error, CustomStringConvertible, Equatable {
enum TomlParseError: Error, CustomStringConvertible, Equatable, LocalizedError {
case semantic(_ backtrace: TomlBacktrace, _ message: String)
case syntax(_ message: String)

Expand All @@ -41,6 +42,9 @@ enum TomlParseError: Error, CustomStringConvertible, Equatable {
case .syntax(let message): message
}
}
var errorDescription: String? {
return description
}
}

typealias ParsedToml<T> = Result<T, TomlParseError>
Expand Down Expand Up @@ -153,9 +157,26 @@ func parseCommandOrCommands(_ raw: TOMLValueConvertible) -> Parsed<[any Command]
}
}

// Note: this is only required due to a TOML parsing bug in TOMLKit which throws SIGABORT in parsing failures
// Should be removed once TOMLKit is patched
private func validateTOMLTableHeaderSyntax(in input: String) throws {
// Matches [[ followed by at least one more [ While ignoring commented lines #
let pattern = #"^(?!\s*#)\s*\[\[(?=\[)"#
let regex = try NSRegularExpression(pattern: pattern, options: .anchorsMatchLines)
let lines = input.components(separatedBy: .newlines)

for (index, line) in lines.enumerated() {
let range = NSRange(location: 0, length: line.utf16.count)
if regex.firstMatch(in: line, options: [], range: range) != nil {
throw TomlParseError.syntax("TOML Parsing Error: Invalid Table Header \n→ expected a header string but found '[' \n→ Location: Line \(index + 1) \n→ Content: \(line)")
}
}
}

func parseConfig(_ rawToml: String) -> (config: Config, errors: [TomlParseError]) { // todo change return value to Result
let rawTable: TOMLTable
do {
try validateTOMLTableHeaderSyntax(in: rawToml)
rawTable = try TOMLTable(string: rawToml)
} catch let e as TOMLParseError {
return (defaultConfig, [.syntax(e.debugDescription)])
Expand Down

0 comments on commit f9b82da

Please sign in to comment.