Skip to content

Commit 71ea82a

Browse files
committed
Fix a potential buffer overrun with a representation change
Indexing is hard
1 parent baa4830 commit 71ea82a

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

Tests/LLVMTests/FileCheck.swift

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ extension CChar {
167167
}
168168
}
169169

170+
extension Character {
171+
fileprivate var isPartOfWord : Bool {
172+
let utf8Value = String(self).utf8.first!
173+
return isalnum(Int32(utf8Value)) != 0 || utf8Value == "-".utf8.first! || utf8Value == "_".utf8.first!
174+
}
175+
}
176+
170177
private func findCheckType(in buf : UnsafeBufferPointer<CChar>, with prefix : String) -> CheckType {
171178
let nextChar = UInt8(buf[prefix.utf8.count])
172179

@@ -245,21 +252,35 @@ private func findFirstMatch(in inbuffer : UnsafeBufferPointer<CChar>, among pref
245252

246253
while !buffer.isEmpty {
247254
let str = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer.baseAddress!), length: buffer.count, encoding: .utf8, freeWhenDone: false)!
248-
let matches = RE.matches(in: str, options: [], range: NSRange(location: 0, length: buffer.count))
249-
guard let prefix = matches.first else {
255+
let match = RE.firstMatch(in: str, options: [], range: NSRange(location: 0, length: str.distance(from: str.startIndex, to: str.endIndex)))
256+
guard let prefix = match else {
250257
return ("", .none, lineNumber, buffer)
251258
}
252-
let skippedPrefix = buffer.substr(0, prefix.range.location)
253-
let prefixStr = substring(in: buffer, with: prefix.range)
259+
let skippedPrefix = substring(in: buffer, with: NSMakeRange(0, prefix.range.location))
260+
let prefixStr = str.substring(
261+
with: Range(
262+
uncheckedBounds: (
263+
str.index(str.startIndex, offsetBy: prefix.range.location),
264+
str.index(str.startIndex, offsetBy: NSMaxRange(prefix.range))
265+
)
266+
)
267+
)
254268

255-
buffer = buffer.dropFront(prefix.range.location)
256-
lineNumber += skippedPrefix.filter({ c in UInt8(c) == "\n".utf8.first! }).count
269+
// HACK: Conversion between the buffer and `String` causes index
270+
// mismatches when searching for strings. We're instead going to do
271+
// something terribly inefficient here: Use the regular expression to
272+
// look for check prefixes, then use Foundation's Data to find their
273+
// actual locations in the buffer.
274+
let bd = Data(buffer: buffer)
275+
let range = bd.range(of: prefixStr.data(using: .utf8)!)!
276+
buffer = buffer.dropFront(range.lowerBound)
277+
lineNumber += skippedPrefix.characters.filter({ c in c == "\n" }).count
257278
// Check that the matched prefix isn't a suffix of some other check-like
258279
// word.
259280
// FIXME: This is a very ad-hoc check. it would be better handled in some
260281
// other way. Among other things it seems hard to distinguish between
261282
// intentional and unintentional uses of this feature.
262-
if skippedPrefix.isEmpty || !skippedPrefix.last!.isPartOfWord {
283+
if skippedPrefix.isEmpty || !skippedPrefix.characters.last!.isPartOfWord {
263284
// Now extract the type.
264285
let CheckTy = findCheckType(in: buffer, with: prefixStr)
265286

@@ -279,11 +300,10 @@ private func findFirstMatch(in inbuffer : UnsafeBufferPointer<CChar>, among pref
279300
}
280301
buffer = buffer.dropFront(loc)
281302
}
282-
303+
283304
return ("", .none, lineNumber, buffer)
284305
}
285306

286-
287307
private func readCheckStrings(in buf : UnsafeBufferPointer<CChar>, withPrefixes prefixes : [String], options: FileCheckOptions, _ RE : NSRegularExpression) -> [CheckString] {
288308
// Keeps track of the line on which CheckPrefix instances are found.
289309
var lineNumber = 1

0 commit comments

Comments
 (0)