Skip to content

Commit 82a5aae

Browse files
committed
TSan: Fix some data race issues found in the tests by Thread Sanitizer.
1 parent f62c026 commit 82a5aae

File tree

4 files changed

+73
-35
lines changed

4 files changed

+73
-35
lines changed

TestFoundation/HTTPServer.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,13 @@ class _TCPSocket {
5151
private let sendFlags: CInt
5252
#endif
5353
private var listenSocket: SOCKET!
54-
private var socketAddress = UnsafeMutablePointer<sockaddr_in>.allocate(capacity: 1)
55-
private var connectionSocket: SOCKET?
54+
private var socketAddress = UnsafeMutablePointer<sockaddr_in>.allocate(capacity: 1)
55+
private var _connectionSocketLock = NSLock()
56+
private var _connectionSocket: SOCKET?
57+
private var connectionSocket: SOCKET? {
58+
get { _connectionSocketLock.synchronized { _connectionSocket } }
59+
set { _connectionSocketLock.synchronized { _connectionSocket = newValue } }
60+
}
5661

5762
private func isNotNegative(r: CInt) -> Bool {
5863
return r != -1
@@ -229,13 +234,15 @@ class _TCPSocket {
229234
}
230235

231236
func closeClient() {
232-
if let connectionSocket = self.connectionSocket {
237+
_connectionSocketLock.synchronized {
238+
if let connectionSocket = _connectionSocket {
233239
#if os(Windows)
234-
closesocket(connectionSocket)
240+
closesocket(connectionSocket)
235241
#else
236-
close(connectionSocket)
242+
close(connectionSocket)
237243
#endif
238-
self.connectionSocket = nil
244+
_connectionSocket = nil
245+
}
239246
}
240247
}
241248

TestFoundation/TestProcess.swift

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -550,19 +550,30 @@ class TestProcess : XCTestCase {
550550
task.executableURL = url
551551
task.arguments = []
552552
let stdoutPipe = Pipe()
553+
let dataLock = NSLock()
553554
task.standardOutput = stdoutPipe
554555

555556
var stdoutData = Data()
556557
stdoutPipe.fileHandleForReading.readabilityHandler = { fh in
557-
stdoutData.append(fh.availableData)
558+
dataLock.synchronized {
559+
stdoutData.append(fh.availableData)
560+
}
558561
}
559562
try task.run()
560563
task.waitUntilExit()
561564
stdoutPipe.fileHandleForReading.readabilityHandler = nil
562-
if let d = try stdoutPipe.fileHandleForReading.readToEnd() {
563-
stdoutData.append(d)
565+
566+
try dataLock.synchronized {
567+
#if DARWIN_COMPATIBILITY_TESTS
568+
// Use old API for now
569+
stdoutData.append(stdoutPipe.fileHandleForReading.availableData)
570+
#else
571+
if let d = try stdoutPipe.fileHandleForReading.readToEnd() {
572+
stdoutData.append(d)
573+
}
574+
#endif
575+
XCTAssertEqual(String(data: stdoutData, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines), "No files specified.")
564576
}
565-
XCTAssertEqual(String(data: stdoutData, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines), "No files specified.")
566577
}
567578

568579

@@ -656,11 +667,11 @@ class _SignalHelperRunner {
656667
}
657668
else if strongSelf.gotReady == true {
658669
if line == "Signal: SIGINT" {
659-
strongSelf._sigIntCount += 1
670+
strongSelf.sQueue.sync { strongSelf._sigIntCount += 1 }
660671
strongSelf.semaphore.signal()
661672
}
662673
else if line == "Signal: SIGCONT" {
663-
strongSelf._sigContCount += 1
674+
strongSelf.sQueue.sync { strongSelf._sigContCount += 1 }
664675
strongSelf.semaphore.signal()
665676
}
666677
}
@@ -717,52 +728,59 @@ internal func runTask(_ arguments: [String], environment: [String: String]? = ni
717728

718729
let stdoutPipe = Pipe()
719730
let stderrPipe = Pipe()
731+
let dataLock = NSLock()
720732
process.standardOutput = stdoutPipe
721733
process.standardError = stderrPipe
722734

723735
var stdoutData = Data()
724736
stdoutPipe.fileHandleForReading.readabilityHandler = { fh in
725-
stdoutData.append(fh.availableData)
737+
dataLock.synchronized {
738+
stdoutData.append(fh.availableData)
739+
}
726740
}
727741

728742
var stderrData = Data()
729743
stderrPipe.fileHandleForReading.readabilityHandler = { fh in
730-
stderrData.append(fh.availableData)
744+
dataLock.synchronized {
745+
stderrData.append(fh.availableData)
746+
}
731747
}
732748

733749
try process.run()
734750
process.waitUntilExit()
735751
stdoutPipe.fileHandleForReading.readabilityHandler = nil
736752
stderrPipe.fileHandleForReading.readabilityHandler = nil
737753

738-
// Drain any data remaining in the pipes
754+
guard process.terminationStatus == 0 else {
755+
throw Error.TerminationStatus(process.terminationStatus)
756+
}
757+
758+
return try dataLock.synchronized {
759+
// Drain any data remaining in the pipes
739760
#if DARWIN_COMPATIBILITY_TESTS
740-
// Use old API for now
741-
stdoutData.append(stdoutPipe.fileHandleForReading.availableData)
742-
stderrData.append(stderrPipe.fileHandleForReading.availableData)
761+
// Use old API for now
762+
stdoutData.append(stdoutPipe.fileHandleForReading.availableData)
763+
stderrData.append(stderrPipe.fileHandleForReading.availableData)
743764
#else
744-
if let d = try stdoutPipe.fileHandleForReading.readToEnd() {
745-
stdoutData.append(d)
746-
}
765+
if let d = try stdoutPipe.fileHandleForReading.readToEnd() {
766+
stdoutData.append(d)
767+
}
747768

748-
if let d = try stderrPipe.fileHandleForReading.readToEnd() {
749-
stderrData.append(d)
750-
}
769+
if let d = try stderrPipe.fileHandleForReading.readToEnd() {
770+
stderrData.append(d)
771+
}
751772
#endif
752773

753-
guard process.terminationStatus == 0 else {
754-
throw Error.TerminationStatus(process.terminationStatus)
755-
}
774+
guard let stdout = String(data: stdoutData, encoding: .utf8) else {
775+
throw Error.UnicodeDecodingError(stdoutData)
776+
}
756777

757-
guard let stdout = String(data: stdoutData, encoding: .utf8) else {
758-
throw Error.UnicodeDecodingError(stdoutData)
759-
}
778+
guard let stderr = String(data: stderrData, encoding: .utf8) else {
779+
throw Error.UnicodeDecodingError(stderrData)
780+
}
760781

761-
guard let stderr = String(data: stderrData, encoding: .utf8) else {
762-
throw Error.UnicodeDecodingError(stderrData)
782+
return (stdout, stderr)
763783
}
764-
765-
return (stdout, stderr)
766784
}
767785

768786
private func parseEnv(_ env: String) throws -> [String: String] {

TestFoundation/TestURLSessionFTP.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,13 @@ class FTPDataTask : NSObject {
6767
var cancelExpectation: XCTestExpectation?
6868
var responseReceivedExpectation: XCTestExpectation?
6969
var hasTransferCompleted = false
70-
public var error = false
70+
71+
private var errorLock = NSLock()
72+
private var _error = false
73+
public var error: Bool {
74+
get { errorLock.synchronized { _error } }
75+
set { errorLock.synchronized { _error = newValue } }
76+
}
7177

7278
init(with expectation: XCTestExpectation) {
7379
dataTaskExpectation = expectation

TestFoundation/Utilities.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,3 +641,10 @@ extension FileHandle: TextOutputStream {
641641
}
642642
}
643643

644+
extension NSLock {
645+
public func synchronized<T>(_ closure: () throws -> T) rethrows -> T {
646+
self.lock()
647+
defer { self.unlock() }
648+
return try closure()
649+
}
650+
}

0 commit comments

Comments
 (0)