Skip to content

Spurious TSan reports #61073

Open
Open
@karwa

Description

@karwa

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:

karwa/swift-url#166

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:

  1. Clone the following repo: https://github.com/karwa/swift-tsan-bug
  2. Run with swift run --sanitize=thread
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    TSanFor issues in the Thread Sanitizer itselfbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.genericsFeature: generic declarations and typesinoutFeature → types: `inout` types

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions