The simplest way to keep the string buffer alive is simply to always grab its
iterator, even if we're not going to use it.  Thanks @milseman for that idea and
@jckarter for the diagnosis help!
This commit is contained in:
Dave Abrahams
2017-07-11 14:58:29 -07:00
parent ba7b699b0f
commit 4f71d9e35c
2 changed files with 20 additions and 4 deletions

View File

@@ -193,6 +193,7 @@ extension String {
/// collection.
public struct Iterator : IteratorProtocol {
init(_ _base: _StringCore) {
self._iterator = _base.makeIterator()
if _base.hasContiguousStorage {
self._baseSet = true
if _base.isASCII {
@@ -211,7 +212,6 @@ extension String {
} else {
self._ascii = false
self._baseSet = false
self._iterator = _base.makeIterator()
}
}
@@ -236,7 +236,7 @@ extension String {
result = _decoder.decode(&(self._base!))
}
} else {
result = _decoder.decode(&(self._iterator!))
result = _decoder.decode(&(self._iterator))
}
switch result {
case .scalarValue(let us):
@@ -252,7 +252,7 @@ extension String {
internal let _ascii: Bool
internal var _asciiBase: UnsafeBufferPointerIterator<UInt8>!
internal var _base: UnsafeBufferPointerIterator<UInt16>!
internal var _iterator: IndexingIterator<_StringCore>!
internal var _iterator: IndexingIterator<_StringCore>
}
/// Returns an iterator over the Unicode scalars that make up this view.

View File

@@ -366,6 +366,22 @@ StringTests.test("[String].joined() -> String") {
_ = s == "" // should compile without error
}
StringTests.test("UnicodeScalarView.Iterator.Lifetime") {
// Tests that String.UnicodeScalarView.Iterator is maintaining the lifetime of
// an underlying String buffer. https://bugs.swift.org/browse/SR-5401
//
// WARNING: it is very easy to write this test so it produces false negatives
// (i.e. passes even when the code is broken). The array, for example, seems
// to be a requirement. So perturb this test with care!
let sources = ["𝓣his 𝓘s 𝓜uch 𝓛onger 𝓣han 𝓐ny 𝓢mall 𝓢tring 𝓑uffer"]
for s in sources {
// Append something to s so that it creates a dynamically-allocated buffer.
let i = (s + "X").unicodeScalars.makeIterator()
expectEqualSequence(s.unicodeScalars, IteratorSequence(i).dropLast(),
"Actual Contents: \(Array(IteratorSequence(i)))")
}
}
var CStringTests = TestSuite("CStringTests")
func getNullUTF8() -> UnsafeMutablePointer<UInt8>? {