Skip to content

Commit b3b1f79

Browse files
committed
Make sure we convert the source to a native UTF-8 string before parsing
It appears like the compiler is now optimizing the `self += ""` away in release builds. Furthermore, we didn't catch the issue since the assertion checking for a native UTF-8 string also gets optimized away in release builds. Fix the issue in two ways: 1. Make the assertion a precondition that also fails in release builds 2. Generate the native UTF-8 string through an iterator that indexes into the foreign string. This is a much more complex transformation and harder to optimize away. It also should be a big performance hit since the Swift standard library also loops over the foreign string to generate a native one.
1 parent e28671a commit b3b1f79

File tree

3 files changed

+13
-2
lines changed

3 files changed

+13
-2
lines changed

Sources/SwiftSyntax/SyntaxParser.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public enum SyntaxParser {
127127
_ filenameForDiagnostics: String,
128128
_ diagnosticEngine: DiagnosticEngine?
129129
) -> RawSyntax {
130-
assert(source.isNativeUTF8)
130+
precondition(source.isNativeUTF8)
131131
let c_parser = swiftparse_parser_create()
132132
defer {
133133
swiftparse_parser_dispose(c_parser)

Sources/SwiftSyntax/Utils.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ extension String {
8080

8181
mutating func makeNativeUTF8IfNeeded() {
8282
if !isNativeUTF8 {
83-
self += ""
83+
self = String(IteratorSequence(self.makeIterator()))
84+
// Assert that we have actually generated a native UTF-8 string.
85+
// We use precondition instead of assert since assert gets optimized away in release builds.
86+
// We do, however, want to check that the optimzier does not optimize the conversion to a UTF-8 native string away in release builds.
87+
precondition(isNativeUTF8)
8488
}
8589
}
8690

Tests/SwiftSyntaxTest/SyntaxTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,11 @@ public class SyntaxTests: XCTestCase {
144144
XCTAssertEqual(Syntax(integerExpr), Syntax(fromProtocol: integerExpr as SyntaxProtocol))
145145
XCTAssertEqual(Syntax(integerExpr), Syntax(fromProtocol: integerExpr as ExprSyntaxProtocol))
146146
}
147+
148+
public func testRunParserOnForeignString() {
149+
// Store the source code in a foreign non-UTF-8 string.
150+
// If SwiftSyntax fails to convert it to a native UTF-8 string, internal assertions should fail.
151+
let sourceNsString = "var 🎉 = 2" as NSString
152+
_ = try? SyntaxParser.parse(source: sourceNsString as String)
153+
}
147154
}

0 commit comments

Comments
 (0)