Description
Describe the bug
I'm seeing TSan reports of access races which don't make sense. They seem to only pop when calling this code in parallel, even though it has no global state (so concurrent invocations should not be touching any shared mutable data anyway).
I get a message that the calling function is a global variable (?!) that is mutated by multiple threads. A user of my package gets a message that 'type metadata instantiation cache for Swift.Optional is a global variable'. It seems to vary quite a bit. More details in the issue:
On the console, I see:
==================
WARNING: ThreadSanitizer: Swift access race (pid=41452)
Modifying access of Swift variable at 0x000100ffe33a by thread T1:
#0 closure #3 in _urlFromBytes_impl<A, B>(_:baseURL:callback:) Parser.swift:74 (spm-tsancheck:x86_64+0x100102a60)
#1 partial apply for closure #3 in _urlFromBytes_impl<A, B>(_:baseURL:callback:) <compiler-generated> (spm-tsancheck:x86_64+0x100102deb)
#2 Either.map<A, B>(left:right:) Either.swift:32 (spm-tsancheck:x86_64+0x1001e4b72)
#3 _urlFromBytes_impl<A, B>(_:baseURL:callback:) Parser.swift:69 (spm-tsancheck:x86_64+0x10010107c)
#4 closure #1 in urlFromBytes<A>(_:baseURL:) Parser.swift:50 (spm-tsancheck:x86_64+0x100100624)
#5 partial apply for closure #1 in urlFromBytes<A>(_:baseURL:) <compiler-generated> (spm-tsancheck:x86_64+0x10010068d)
#6 thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x1001011cb)
#7 partial apply for thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x10010129f)
#8 UnsafeBufferPointer.withContiguousStorageIfAvailable<A>(_:) <null>:2 (libswiftCore.dylib:x86_64+0x25296e)
#9 WebURL.init<A>(utf8:) WebURL.swift:92 (spm-tsancheck:x86_64+0x100270a34)
#10 closure #1 in WebURL.init<A>(_:) WebURL.swift:54 (spm-tsancheck:x86_64+0x100270995)
#11 thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x1001011cb)
#12 partial apply for thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x100270b6f)
#13 String.UTF8View.withContiguousStorageIfAvailable<A>(_:) <null>:2 (libswiftCore.dylib:x86_64+0x1ba109)
#14 WebURL.init<A>(_:) WebURL.swift:54 (spm-tsancheck:x86_64+0x1002707e6)
#15 closure #1 in doIt() main.swift:6 (spm-tsancheck:x86_64+0x100277dd8)
#16 partial apply for thunk for @callee_guaranteed (@unowned Int) -> () <null>:2 (libswiftDispatch.dylib:x86_64+0x5f90)
#17 _dispatch_client_callout2 <null>:2 (libdispatch.dylib:x86_64+0x3349)
Previous modifying access of Swift variable at 0x000100ffe33a by main thread:
#0 closure #3 in _urlFromBytes_impl<A, B>(_:baseURL:callback:) Parser.swift:74 (spm-tsancheck:x86_64+0x100102a60)
#1 partial apply for closure #3 in _urlFromBytes_impl<A, B>(_:baseURL:callback:) <compiler-generated> (spm-tsancheck:x86_64+0x100102deb)
#2 Either.map<A, B>(left:right:) Either.swift:32 (spm-tsancheck:x86_64+0x1001e4b72)
#3 _urlFromBytes_impl<A, B>(_:baseURL:callback:) Parser.swift:69 (spm-tsancheck:x86_64+0x10010107c)
#4 closure #1 in urlFromBytes<A>(_:baseURL:) Parser.swift:50 (spm-tsancheck:x86_64+0x100100624)
#5 partial apply for closure #1 in urlFromBytes<A>(_:baseURL:) <compiler-generated> (spm-tsancheck:x86_64+0x10010068d)
#6 thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x1001011cb)
#7 partial apply for thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x10010129f)
#8 UnsafeBufferPointer.withContiguousStorageIfAvailable<A>(_:) <null>:2 (libswiftCore.dylib:x86_64+0x25296e)
#9 WebURL.init<A>(utf8:) WebURL.swift:92 (spm-tsancheck:x86_64+0x100270a34)
#10 closure #1 in WebURL.init<A>(_:) WebURL.swift:54 (spm-tsancheck:x86_64+0x100270995)
#11 thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x1001011cb)
#12 partial apply for thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<UInt8>) -> (@owned WebURL?, @error @owned Error) <compiler-generated> (spm-tsancheck:x86_64+0x100270b6f)
#13 String.UTF8View.withContiguousStorageIfAvailable<A>(_:) <null>:2 (libswiftCore.dylib:x86_64+0x1ba109)
#14 WebURL.init<A>(_:) WebURL.swift:54 (spm-tsancheck:x86_64+0x1002707e6)
#15 closure #1 in doIt() main.swift:6 (spm-tsancheck:x86_64+0x100277dd8)
#16 partial apply for thunk for @callee_guaranteed (@unowned Int) -> () <null>:2 (libswiftDispatch.dylib:x86_64+0x5f90)
#17 _dispatch_client_callout2 <null>:2 (libdispatch.dylib:x86_64+0x3349)
#18 _swift_dispatch_apply_current <null>:2 (libswiftDispatch.dylib:x86_64+0x6051)
#19 main main.swift:10 (spm-tsancheck:x86_64+0x100277af5)
Location is global 'urlFromBytes<A>(_:baseURL:)' at 0x000000000000 (spm-tsancheck+0x00010010033a)
Thread T1 (tid=1001327, running) is a GCD worker thread
SUMMARY: ThreadSanitizer: Swift access race Parser.swift:74 in closure #3 in _urlFromBytes_impl<A, B>(_:baseURL:callback:)
==================
Lots of details about this are suspicious. Particularly the 'location' at address 0.
Steps To Reproduce
Steps to reproduce the behavior:
- Clone the following repo: https://github.com/karwa/swift-tsan-bug
- Run with
swift run --sanitize=thread
- If that fails to produce a TSan report, try
swift test --sanitize=thread
Expected behavior
There is no shared mutable state here (at least, not from my code; the Swift runtime may have shared mutable state). TSan should not report any data races. Whether this is a bug in TSan, or in the Swift runtime, I don't know; but I'm quite sure there isn't an actual data race here.
Screenshots
There are some screenshots in the linked bug report: karwa/swift-url#166
Environment (please fill out the following information)
- OS: macOS 12.5.1
- Xcode Version/Tag/Branch: 13.4.1, 14RC, also reproduced using a recent 5.7 nightly