Skip to content

Commit 6e3d8b0

Browse files
authored
Follow up fix for buffer overflow (#684)
Start the outer buffer with the capacity of `initialSize + 1` so later we can null terminate on the index of `initialSize`, assuming the return length is smaller or equal to `initialSize`. We don't bother to verify the assumption since that'd be a user error. Also fix a terrible copy-pasta error: We should null-terminate the inner buffer, not the outer buffer. Fixed 129806508
1 parent 7ee35fb commit 6e3d8b0

File tree

2 files changed

+10
-2
lines changed

2 files changed

+10
-2
lines changed

Sources/FoundationInternationalization/ICU/ICU+Foundation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ internal func _withFixedUCharBuffer(size: Int32 = ULOC_FULLNAME_CAPACITY + ULOC_
104104
/// Allocate a buffer with `size` `CChar`s and execute the given block.
105105
/// The closure should return the actual length of the string, or nil if there is an error in the ICU call or the result is zero length.
106106
internal func _withResizingCharBuffer(initialSize: Int32 = 32, _ body: (UnsafeMutablePointer<CChar>, Int32, inout UErrorCode) -> Int32?) -> String? {
107-
withUnsafeTemporaryAllocation(of: CChar.self, capacity: Int(initialSize)) {
107+
withUnsafeTemporaryAllocation(of: CChar.self, capacity: Int(initialSize + 1)) {
108108
buffer in
109109
var status = U_ZERO_ERROR
110110
if let len = body(buffer.baseAddress!, initialSize, &status) {
@@ -114,7 +114,7 @@ internal func _withResizingCharBuffer(initialSize: Int32 = 32, _ body: (UnsafeMu
114114
var innerStatus = U_ZERO_ERROR
115115
if let innerLen = body(innerBuffer.baseAddress!, len + 1, &innerStatus) {
116116
if innerStatus.isSuccess && innerLen > 0 {
117-
buffer[Int(innerLen)] = 0
117+
innerBuffer[Int(innerLen)] = 0
118118
return String(validatingUTF8: innerBuffer.baseAddress!)
119119
}
120120
}

Tests/FoundationInternationalizationTests/StringTests+Locale.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ final class StringLocaleTests: XCTestCase {
143143

144144
test(nil, "", "") // 0x1F88
145145
test("en", "", "")
146+
test("en", "SOMEVERYVERYVERYVERYVERYVERYVERYVERYVERYLONGSTRING", "someveryveryveryveryveryveryveryveryverylongstring")
146147
test("el_GR", "", "")
147148

148149
// Turkik
@@ -154,5 +155,12 @@ final class StringLocaleTests: XCTestCase {
154155
test("en", "İİ", "i̇i̇")
155156
test("tr", "İİ", "ii")
156157
}
158+
159+
func testFuzzFailure() throws {
160+
let input = String(data: Data(base64Encoded: "77+977+977+977+977+977+977+977+977+977+9Cg==")!, encoding: .utf8)!
161+
_ = input.lowercased(with: Locale(identifier: "en_US"))
162+
_ = input.capitalized(with: Locale(identifier: "en_US"))
163+
_ = input.capitalized(with: Locale(identifier: "en_US"))
164+
}
157165
}
158166

0 commit comments

Comments
 (0)