Skip to content

Commit 49e45ef

Browse files
authored
Fix error handling for array parsing (#18)
Addresses an error introduced when rearranging error handling in array parsers. The validation of `count` being non-negative was dropped at some point along the way; this change brings that check back and switches the `Array(parsing:count:parser:)` initializer to throw `ThrownParsingError` instead of having a generic error type parameter.
1 parent 7c480d6 commit 49e45ef

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

Sources/BinaryParsing/Parser Types/ParsingError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ extension ParsingError.Status: CustomStringConvertible {
121121
/// In a build for embedded Swift, `ThrownParsingError` instead aliases the
122122
/// specific `ParsingError` type. Because embedded Swift supports only
123123
/// fully-typed throws, and not the existential `any Error`, this allows you to
124-
/// still take use error-throwing APIs in an embedded context.
124+
/// still use error-throwing APIs in an embedded context.
125125
public typealias ThrownParsingError = any Error
126126
#else
127127
// Documentation is built using the non-embedded build.

Sources/BinaryParsing/Parsers/Array.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ extension Array {
8080
count: some FixedWidthInteger,
8181
parser: (inout ParserSpan) throws -> Element
8282
) throws {
83-
let count = try Int(throwingOnOverflow: count)
83+
guard let count = Int(exactly: count), count >= 0 else {
84+
throw ParsingError(statusOnly: .invalidValue)
85+
}
8486
self = []
8587
self.reserveCapacity(count)
8688
// This doesn't throw (e.g. on empty) because `parser` can produce valid
@@ -118,11 +120,14 @@ extension Array {
118120
/// - Throws: An error if one is thrown from `parser`.
119121
@inlinable
120122
@lifetime(&input)
121-
public init<E>(
123+
public init(
122124
parsing input: inout ParserSpan,
123125
count: Int,
124-
parser: (inout ParserSpan) throws(E) -> Element
125-
) throws(E) {
126+
parser: (inout ParserSpan) throws(ThrownParsingError) -> Element
127+
) throws(ThrownParsingError) {
128+
guard count >= 0 else {
129+
throw ParsingError(statusOnly: .invalidValue)
130+
}
126131
self = []
127132
self.reserveCapacity(count)
128133
// This doesn't throw (e.g. on empty) because `parser` can produce valid

Tests/BinaryParsingTests/ArrayParsingTests.swift

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,23 @@ struct ArrayParsingTests {
2121

2222
@Test
2323
func parseRemainingBytes() throws {
24-
try testBuffer.withParserSpan { span in
25-
let parsedArray = try Array(parsingRemainingBytes: &span)
24+
testBuffer.withParserSpan { span in
25+
let parsedArray = Array(parsingRemainingBytes: &span)
2626
#expect(parsedArray == testBuffer)
2727
#expect(span.count == 0)
2828
}
2929

3030
// Test parsing after consuming part of the buffer
3131
try testBuffer.withParserSpan { span in
3232
try span.seek(toRelativeOffset: 3)
33-
let parsedArray = try Array(parsingRemainingBytes: &span)
33+
let parsedArray = Array(parsingRemainingBytes: &span)
3434
#expect(parsedArray[...] == testBuffer.dropFirst(3))
3535
#expect(span.count == 0)
3636
}
3737

3838
// Test with an empty span
39-
try emptyBuffer.withParserSpan { span in
40-
let parsedArray = try [UInt8](parsingRemainingBytes: &span)
39+
emptyBuffer.withParserSpan { span in
40+
let parsedArray = [UInt8](parsingRemainingBytes: &span)
4141
#expect(parsedArray.isEmpty)
4242
}
4343
}
@@ -68,6 +68,14 @@ struct ArrayParsingTests {
6868
}
6969
#expect(span.count == testBuffer.count)
7070
}
71+
72+
// Negative 'byteCount'
73+
testBuffer.withParserSpan { span in
74+
#expect(throws: ParsingError.self) {
75+
_ = try [UInt8](parsing: &span, byteCount: -1)
76+
}
77+
#expect(span.count == testBuffer.count)
78+
}
7179
}
7280

7381
@Test
@@ -118,13 +126,21 @@ struct ArrayParsingTests {
118126
#expect(span.count == 0)
119127
}
120128

121-
// Non-'Int' count that would overflow
122-
_ = testBuffer.withParserSpan { span in
129+
// Error checking
130+
testBuffer.withParserSpan { span in
131+
// Overflow when 'Int'
123132
#expect(throws: ParsingError.self) {
124133
_ = try [UInt8](parsing: &span, count: UInt.max) { input in
125134
try UInt8(parsing: &input)
126135
}
127136
}
137+
138+
// Negative count
139+
#expect(throws: ParsingError.self) {
140+
_ = try [UInt8](parsing: &span, count: -1) { input in
141+
try UInt8(parsing: &input)
142+
}
143+
}
128144
}
129145
}
130146

0 commit comments

Comments
 (0)