Skip to content

Commit 02688df

Browse files
committed
[TSan] Add positive test for TSan + Dispatch on Linux
1) Enable tests that use `import Dispatch` on Linux. Add substitution `%import-libdispatch` that needs to be used for all cross-platform tests (i.e., tests that are intended to be run on other platforms than Darwin) that do `import Dispatch` or enable thread sanitizer. 2) Make sure as many existing Dispatch and TSan tests as possible run on Linux. Mark tests that would require substantial work with `UNSUPPORTED: OS=linux-gnu`. 3) Add integration-style Swift test that shows that TSan finds a simple race when using `Dispatch.async` incorrectly. A more complete test suite for TSan's libdispatch support lives on the LLVM/compiler-rt side. rdar://problem/49177535
1 parent 14a20ee commit 02688df

23 files changed

+143
-75
lines changed

test/ClangImporter/Dispatch_test.swift

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-typecheck-verify-swift
22

33
// REQUIRES: libdispatch
4+
// UNSUPPORTED: OS=linux-gnu
45

56
import Dispatch
67

test/IRGen/tsan-attributes.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22

33
// RUN: %target-swift-frontend -emit-ir -sanitize=thread %s | %FileCheck %s -check-prefix=TSAN
44

5-
// TSan is currently only supported on 64 bit mac and simulators.
6-
// (We do not test the simulators here.)
7-
// REQUIRES: CPU=x86_64, OS=macosx
5+
// TSan is only supported on 64 bit.
6+
// REQUIRES: PTRSIZE=64
87

98
// TSAN: define {{.*}} @"$s4main4testyyF"() [[DEFAULT_ATTRS:#[0-9]+]]
109
public func test() {

test/IRGen/tsan_coroutines.swift

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// This test case used to crash when tsan ran before co-routine lowering.
22
// RUN: %target-swift-frontend -emit-ir -sanitize=thread %s | %FileCheck %s
33

4-
// TSan is currently only supported on 64 bit mac and simulators.
5-
// (We do not test the simulators here.)
6-
// REQUIRES: CPU=x86_64, OS=macosx
4+
// TSan is only supported on 64 bit.
5+
// REQUIRES: PTRSIZE=64
76

87
public class C { }
98

@@ -23,7 +22,7 @@ extension Foobar {
2322
}
2423

2524
// We used to crash emitting the subscript function.
26-
// CHECK: define swiftcc { i8*, %T15tsan_coroutines1CC* } @"$s15tsan_coroutines6FoobarVyAA1CCAC5IndexVcir"
25+
// CHECK: define{{( dllexport| protected)?}} swiftcc { i8*, %T15tsan_coroutines1CC* } @"$s15tsan_coroutines6FoobarVyAA1CCAC5IndexVcir"
2726
@_borrowed
2827
public subscript(position: Index) -> C {
2928
return things.values[position.myIndex]

test/Profiler/instrprof_tsan.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %target-swift-frontend -emit-ir -profile-generate -sanitize=thread %s | %FileCheck %s
22

3-
// REQUIRES: OS=macosx
4-
// REQUIRES: CPU=x86_64
3+
// TSan is only supported on 64 bit.
4+
// REQUIRES: PTRSIZE=64
55

66
// CHECK: define {{.*}}empty
77
// CHECK-NOT: load{{.*}}empty

test/Runtime/lazy_witness_table_cycle.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %target-run-simple-swift
22
// REQUIRES: executable_test
3-
// REQUIRES: objc_interop
3+
// REQUIRES: foundation
44

55
// SR-5958
66
import Foundation

test/SILGen/tsan_instrumentation.swift

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// RUN: %target-swift-emit-silgen -sanitize=thread %s | %FileCheck %s
2-
// REQUIRES: tsan_runtime
32

4-
// FIXME: This should be covered by "tsan_runtime"; older versions of Apple OSs
5-
// don't support TSan.
6-
// UNSUPPORTED: remote_run
3+
// TSan is only supported on 64 bit.
4+
// REQUIRES: PTRSIZE=64
75

86
func takesInout(_ p: inout Int) { }
97
func takesInout(_ p: inout MyStruct) { }

test/Sanitizers/tsan-emptyarraystorage.swift

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// RUN: %target-run %t_tsan-binary 2>&1 | %FileCheck %s
44
// REQUIRES: executable_test
55
// REQUIRES: tsan_runtime
6+
// REQUIRES: foundation
67
// UNSUPPORTED: OS=tvos
78

89
// FIXME: This should be covered by "tsan_runtime"; older versions of Apple OSs
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-swiftc_driver %s -g -sanitize=thread %import-libdispatch -o %t_tsan-binary
2+
// RUN: %target-codesign %t_tsan-binary
3+
// RUN: not env %env-TSAN_OPTIONS=abort_on_error=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s
4+
// REQUIRES: executable_test
5+
// REQUIRES: tsan_runtime
6+
// UNSUPPORTED: OS=tvos
7+
8+
// FIXME: This should be covered by "tsan_runtime"; older versions of Apple OSs
9+
// don't support TSan.
10+
// UNSUPPORTED: remote_run
11+
12+
// Test ThreadSanitizer execution end-to-end with libdispatch.
13+
14+
import Dispatch
15+
16+
let sync1 = DispatchSemaphore(value: 0)
17+
let sync2 = DispatchSemaphore(value: 0)
18+
let finish = DispatchSemaphore(value: 0)
19+
20+
let q = DispatchQueue(label: "q", attributes: .concurrent)
21+
22+
var racy = 1
23+
24+
q.async {
25+
sync1.wait()
26+
sync2.signal()
27+
racy = 2
28+
finish.signal()
29+
}
30+
q.async {
31+
sync1.signal()
32+
sync2.wait()
33+
racy = 3
34+
finish.signal()
35+
}
36+
37+
finish.wait()
38+
finish.wait()
39+
40+
print("Done!")
41+
42+
// CHECK: ThreadSanitizer: data race
43+
// CHECK: Done!

test/Sanitizers/tsan-norace-block-release.swift

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
1-
// RUN: %target-swiftc_driver %s -g -sanitize=thread -target %sanitizers-target-triple -o %t_tsan-binary
1+
// RUN: %target-swiftc_driver %s -g -sanitize=thread %import-libdispatch -target %sanitizers-target-triple -o %t_tsan-binary
22
// RUN: %target-codesign %t_tsan-binary
3-
// RUN: env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s
3+
// RUN: env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s --implicit-check-not='ThreadSanitizer'
44
// REQUIRES: executable_test
5-
// REQUIRES: objc_interop
65
// REQUIRES: tsan_runtime
76

87
// FIXME: This should be covered by "tsan_runtime"; older versions of Apple OSs
98
// don't support TSan.
109
// UNSUPPORTED: remote_run
1110

1211
// Test that we do not report a race on block release operation.
13-
import Foundation
14-
15-
public class Sad : NSObject {
12+
import Dispatch
13+
#if canImport(Darwin)
14+
import Darwin
15+
#elseif canImport(Glibc)
16+
import Glibc
17+
#else
18+
#error("Unsupported platform")
19+
#endif
20+
21+
public class Sad {
1622
private var _source: DispatchSourceTimer?
17-
public override init() {
23+
public init() {
1824
_source = DispatchSource.makeTimerSource()
1925

2026
// If this line is commented out no data race.
2127
_source?.setEventHandler(handler: globalFuncHandler)
2228

23-
super.init()
2429
_source?.resume()
2530
}
2631
deinit {
@@ -40,4 +45,3 @@ sleep(1)
4045
print("Done.")
4146

4247
// CHECK: Done.
43-
// CHECK-NOT: ThreadSanitizer: data race

test/Sanitizers/tsan-norace-deinit-run-time.swift

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
// RUN: %target-swiftc_driver %s -g -sanitize=thread -target %sanitizers-target-triple -o %t_tsan-binary
1+
// RUN: %target-swiftc_driver %s -g -sanitize=thread %import-libdispatch -target %sanitizers-target-triple -o %t_tsan-binary
22
// RUN: %target-codesign %t_tsan-binary
3-
// RUN: env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s
3+
// RUN: env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s --implicit-check-not='ThreadSanitizer'
44
// REQUIRES: executable_test
5-
// REQUIRES: objc_interop
65
// REQUIRES: tsan_runtime
76

87
// FIXME: This should be covered by "tsan_runtime"; older versions of Apple OSs
98
// don't support TSan.
109
// UNSUPPORTED: remote_run
1110

1211
// Test that we do not report a race on deinit; the synchronization is guaranteed by runtime.
13-
import Foundation
14-
15-
public class TestDeallocObject : NSObject {
12+
import Dispatch
13+
#if canImport(Darwin)
14+
import Darwin
15+
#elseif canImport(Glibc)
16+
import Glibc
17+
#else
18+
#error("Unsupported platform")
19+
#endif
20+
21+
public class TestDeallocObject {
1622
public var v : Int
17-
public override init() {
23+
public init() {
1824
v = 1
1925
}
2026

@@ -33,7 +39,7 @@ public class TestDeallocObject : NSObject {
3339
}
3440
}
3541

36-
if (true) {
42+
do {
3743
var tdo : TestDeallocObject = TestDeallocObject()
3844
tdo.accessMember()
3945

@@ -52,4 +58,3 @@ if (true) {
5258
print("Done.")
5359

5460
// CHECK: Done.
55-
// CHECK-NOT: ThreadSanitizer: data race

test/Sanitizers/tsan.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=thread -o %t_tsan-binary
1+
// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=thread %import-libdispatch -o %t_tsan-binary
22
// RUN: %target-codesign %t_tsan-binary
33
// RUN: not env %env-TSAN_OPTIONS="abort_on_error=0" %target-run %t_tsan-binary 2>&1 | %FileCheck %s
44
// REQUIRES: executable_test

test/lit.cfg

+27-26
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,10 @@ if run_vendor == 'apple':
656656
config.target_codesign = "codesign -f -s -"
657657
config.target_runtime = "objc"
658658

659+
config.available_features.add('libdispatch')
660+
config.available_features.add('foundation')
661+
config.available_features.add('objc_interop')
662+
659663
xcrun_prefix = (
660664
"xcrun --toolchain %s --sdk %r" %
661665
(config.darwin_xcrun_toolchain, config.variant_sdk))
@@ -905,6 +909,21 @@ elif run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'windows-cygnus', 'wi
905909
config.target_sdk_name = "linux"
906910
config.target_runtime = "native"
907911
config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract")
912+
913+
libdispatch_build_dir = make_path(config.swift_obj_root, os.pardir,
914+
'libdispatch%s' % config.variant_suffix, 'src')
915+
libdispatch_build_artifacts = [
916+
make_path(libdispatch_build_dir, 'libdispatch.so'),
917+
make_path(libdispatch_build_dir, 'libswiftDispatch.so'),
918+
make_path(libdispatch_build_dir, 'swift', 'Dispatch.swiftmodule')]
919+
if (all(os.path.exists(p) for p in libdispatch_build_artifacts)):
920+
config.available_features.add('libdispatch')
921+
config.libdispatch_build_dir = libdispatch_build_dir
922+
libdispatch_source_dir = make_path(config.swift_src_root, os.pardir, 'swift-corelibs-libdispatch')
923+
libdispatch_swift_module_dir = make_path(libdispatch_build_dir, 'swift')
924+
config.import_libdispatch = ('-I %s -I %s -L %s'
925+
% (libdispatch_source_dir, libdispatch_swift_module_dir, libdispatch_build_dir))
926+
908927
config.target_build_swift = (
909928
'%s -target %s %s %s %s %s %s'
910929
% (config.swiftc, config.variant_triple, resource_dir_opt, mcp_opt,
@@ -1214,7 +1233,7 @@ runtime_libs = {
12141233
'fuzzer': 'fuzzer_runtime'
12151234
}
12161235

1217-
if run_ptrsize != "32":
1236+
if run_ptrsize == '64' and 'libdispatch' in config.available_features:
12181237
runtime_libs['tsan'] = 'tsan_runtime'
12191238

12201239
check_runtime_libs(runtime_libs)
@@ -1312,14 +1331,15 @@ if os.path.exists(static_libswiftCore_path):
13121331
# default Swift tests to use the just-built libraries
13131332
target_stdlib_path = platform_module_dir
13141333
if not kIsWindows:
1334+
libdispatch_path = getattr(config, 'libdispatch_build_dir', '')
13151335
if 'use_os_stdlib' not in lit_config.params:
13161336
lit_config.note('Testing with the just-built libraries at ' + target_stdlib_path)
13171337
config.target_run = (
13181338
"/usr/bin/env "
13191339
"DYLD_LIBRARY_PATH='{0}' " # Apple option
1320-
"LD_LIBRARY_PATH='{0}' " # Linux option
1340+
"LD_LIBRARY_PATH='{0}:{1}' " # Linux option
13211341
"SIMCTL_CHILD_DYLD_LIBRARY_PATH='{0}' " # Simulator option
1322-
.format(target_stdlib_path)) + config.target_run
1342+
.format(target_stdlib_path, libdispatch_path)) + config.target_run
13231343
else:
13241344
os_stdlib_path = ''
13251345
if run_vendor == 'apple':
@@ -1330,9 +1350,9 @@ if not kIsWindows:
13301350
config.target_run = (
13311351
"/usr/bin/env "
13321352
"DYLD_LIBRARY_PATH='{0}' " # Apple option
1333-
"LD_LIBRARY_PATH='{0}' " # Linux option
1353+
"LD_LIBRARY_PATH='{0}:{1}' " # Linux option
13341354
"SIMCTL_CHILD_DYLD_LIBRARY_PATH='{0}' " # Simulator option
1335-
.format(all_stdlib_path)) + config.target_run
1355+
.format(all_stdlib_path, libdispatch_path)) + config.target_run
13361356

13371357
if not getattr(config, 'target_run_simple_swift', None):
13381358
config.target_run_simple_swift_parameterized = \
@@ -1376,7 +1396,7 @@ if not getattr(config, 'target_run_simple_swift', None):
13761396
% (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run))
13771397

13781398
#
1379-
# When changing substitutions, update docs/Testing.rst.
1399+
# When changing substitutions, update docs/Testing.md.
13801400
#
13811401

13821402
config.substitutions.append(('%target-runtime', config.target_runtime))
@@ -1498,6 +1518,7 @@ config.substitutions.append(('%FileCheck',
14981518
config.filecheck,
14991519
'--enable-windows-compatibility' if kIsWindows else '')))
15001520
config.substitutions.append(('%raw-FileCheck', pipes.quote(config.filecheck)))
1521+
config.substitutions.append(('%import-libdispatch', getattr(config, 'import_libdispatch', '')))
15011522

15021523
if config.lldb_build_root != "":
15031524
config.available_features.add('lldb')
@@ -1526,25 +1547,5 @@ if platform.system() == 'Linux':
15261547
config.available_features.add("LinuxDistribution=" + distributor + '-' + release)
15271548
lit_config.note('Running tests on %s-%s' % (distributor, release))
15281549

1529-
if run_vendor == 'apple':
1530-
config.available_features.add('libdispatch')
1531-
config.available_features.add('foundation')
1532-
config.available_features.add('objc_interop')
1533-
else:
1534-
# TODO(yln): Works with the packaged swift distribution, but not during build.
1535-
# We need to make libdispatch/foundation available in the test resource directory
1536-
# or pass along the proper library include paths in the compiler invocations that are used
1537-
# to build the tests.
1538-
def has_lib(name):
1539-
return False
1540-
1541-
if has_lib('dispatch'):
1542-
config.available_features.add('libdispatch')
1543-
else:
1544-
# TSan runtime requires libdispatch on non-Apple platforms
1545-
config.available_features.discard('tsan_runtime')
1546-
1547-
if has_lib('Foundation'):
1548-
config.available_features.add('foundation')
15491550

15501551
lit_config.note("Available features: " + ", ".join(sorted(config.available_features)))

test/stdlib/Dispatch.swift

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-run-simple-swift
22
// REQUIRES: executable_test
33
// REQUIRES: libdispatch
4+
// UNSUPPORTED: OS=linux-gnu
45

56
import Dispatch
67
import StdlibUnittest

test/stdlib/DispatchData.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-build-swift -swift-version 4 %s -o %t/a.out-4 && %target-codesign %t/a.out-4 && %target-run %t/a.out-4
3-
// RUN: %target-build-swift -swift-version 4.2 %s -o %t/a.out-4.2 && %target-codesign %t/a.out-4.2 && %target-run %t/a.out-4.2
2+
// RUN: %target-build-swift -swift-version 4 %s %import-libdispatch -o %t/a.out-4 && %target-codesign %t/a.out-4 && %target-run %t/a.out-4
3+
// RUN: %target-build-swift -swift-version 4.2 %s %import-libdispatch -o %t/a.out-4.2 && %target-codesign %t/a.out-4.2 && %target-run %t/a.out-4.2
44
// REQUIRES: executable_test
55
// REQUIRES: libdispatch
66

@@ -22,11 +22,12 @@ DispatchAPI.test("dispatch_data_t deallocator") {
2222
let q = DispatchQueue(label: "dealloc queue")
2323
var t = 0
2424

25-
autoreleasepool {
25+
do {
2626
let size = 1024
2727
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
2828
let _ = DispatchData(bytesNoCopy: UnsafeBufferPointer(start: p, count: size), deallocator: .custom(q, {
2929
t = 1
30+
p.deallocate();
3031
}))
3132
}
3233

test/stdlib/DispatchDeprecationMacOS.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// RUN: %swift -typecheck -target x86_64-apple-macosx10.9 -verify -sdk %sdk %s
22
// REQUIRES: OS=macosx
3-
// REQUIRES: objc_interop
3+
// REQUIRES: libdispatch
44

5-
import Foundation
65
import Dispatch
76

87
// Don't warn because these APIs were deprecated in macOS 10.10 and the

test/stdlib/DispatchDeprecationWatchOS.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// RUN: %swift -typecheck -target i386-apple-watchos2.0 -verify -sdk %sdk %s
22
// REQUIRES: CPU=i386, OS=watchos
3-
// REQUIRES: objc_interop
3+
// REQUIRES: libdispatch
44

5-
import Foundation
65
import Dispatch
76

87
// These are deprecated on all versions of watchOS.

test/stdlib/DispatchRenames.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift %import-libdispatch
22
// REQUIRES: libdispatch
33

44
import Dispatch

0 commit comments

Comments
 (0)