Skip to content

SyntaxArena: thread safety part 2 #857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 30, 2022

Conversation

CodaFi
Copy link
Contributor

@CodaFi CodaFi commented Sep 28, 2022

Restore Rintaro's original patch with a few adjustments:

  • Sequester the platform-specific bits into a common type. If a platform is not present here, it'll just blow up instead of enabling data races.
  • Expand the available platforms supported to include Windows
  • Use pthread_mutex_t on Darwin platforms for now - which was the driver of the revert

@CodaFi CodaFi requested a review from rintaro September 28, 2022 17:25
@CodaFi CodaFi requested a review from ahoppen as a code owner September 28, 2022 17:25
@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 28, 2022

@swift-ci test

@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 28, 2022

CC @jpsim

@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 29, 2022

Swift-CI had a hiccup this morning

@swift-ci test

jpsim added a commit to realm/SwiftLint that referenced this pull request Sep 29, 2022
@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 29, 2022

@swift-ci test

@@ -37,7 +37,18 @@ struct PlatformMutex {
let storage = allocator.allocate(Primitive.self, count: 1).baseAddress!
storage.initialize(to: Primitive())
#if canImport(Darwin) || canImport(Glibc)
pthread_mutex_init(storage, nil)
#if canImport(Darwin)
// HACK: On Darwin, the value of PTHREAD_MUTEX_INITIALIZER installs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, what?!

@jpsim
Copy link
Contributor

jpsim commented Sep 29, 2022

I'm still seeing a race with the latest commit (2556643):

Linting Swift files in current working directory
1 of 519 [                              ] ETA: 0s (26637 files/s)
The `anyobject_protocol` rule is now deprecated and will be completely removed in a future release.
swiftlint(88948,0x16b657000) malloc: Heap corruption detected, free list is damaged at 0x6000020a0280
*** Incorrect guard value: 0
swiftlint(88948,0x16b657000) malloc: *** set a breakpoint in malloc_error_break to debug
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
Stack dump:
0.	Compilation construction
1.	Building compilation jobs
2.	While building jobs for driver Action compile of type none
3.	While determining output for driver CommandOutput
{
    PrimaryOutputType = none;
    Inputs = [
        CommandInputPair {
            Base = -, 
            Primary = -
        }];
    DerivedOutputFileMap = {

    };
}

And with TSan enabled:

$ bazel run --config=release --features=tsan @SwiftLint//:swiftlint -- --no-cache --progress
swiftlint(89773,0x1049f8580) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
Linting Swift files in current working directory
1 of 519 [                              ] ETA: 0s (14906 files/s)
The `anyobject_protocol` rule is now deprecated and will be completely removed in a future release.
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
ThreadSanitizer:DEADLYSIGNAL
==89773==ERROR: ThreadSanitizer: SEGV on unknown address 0x00040dbd82e0 (pc 0x0001b4b229e8 bp 0x00016dcc5820 sp 0x00016dcc5270 T2567574)
==89773==The signal is caused by a UNKNOWN memory access.
    #0 cache_getImp <null>:81551592 (libobjc.A.dylib:arm64e+0x79e8)
    #1 _objc_msgSend_uncached <null>:81551592 (libobjc.A.dylib:arm64e+0x78e0)
    #2 CFStringGetBytes <null>:81551592 (CoreFoundation:arm64e+0x11154)
    #3 CFStringAppend <null>:81551592 (CoreFoundation:arm64e+0x3334c)
    #4 -[NSPlaceholderMutableString initWithString:] <null>:81551592 (Foundation:arm64e+0xaf78)
    #5 -[NSString stringByReplacingOccurrencesOfString:withString:options:range:] <null>:81551592 (Foundation:arm64e+0x2fc44)
    #6 StringProtocol.replacingOccurrences<A, B>(of:with:options:range:) <null>:81551592 (libswiftFoundation.dylib:arm64e+0x8b84)
    #7 FileNameRule.validate(file:) <null>:81551592 (swiftlint:arm64+0x1001f3464)
    #8 protocol witness for Rule.validate(file:using:compilerArguments:) in conformance FileNameRule <null>:81551592 (swiftlint:arm64+0x10014a814)
    #9 specialized Rule.lint(file:regions:benchmark:storage:configuration:superfluousDisableCommandRule:compilerArguments:) <null>:81551592 (swiftlint:arm64+0x100100e04)
    #10 closure #2 in CollectedLinter.getStyleViolations(using:benchmark:) <null>:81551592 (swiftlint:arm64+0x1000fb634)
    #11 partial apply for closure #2 in CollectedLinter.getStyleViolations(using:benchmark:) <null>:81551592 (swiftlint:arm64+0x100100988)
    #12 specialized closure #1 in closure #1 in Array.parallelMap<A>(transform:) <null>:81551592 (swiftlint:arm64+0x1000caa08)
    #13 partial apply for specialized closure #1 in closure #1 in Array.parallelMap<A>(transform:) <null>:81551592 (swiftlint:arm64+0x1000cd28c)
    #14 partial apply for thunk for @callee_guaranteed (@unowned Int) -> () <null>:81551592 (libswiftDispatch.dylib:arm64e+0x6070)
    #15 thunk for @escaping @callee_guaranteed (@unowned Int) -> () <null>:81551592 (libswiftDispatch.dylib:arm64e+0x609c)
    #16 __wrap_dispatch_apply_block_invoke <null>:81551592 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x86518)
    #17 _dispatch_client_callout2 <null>:81551592 (libdispatch.dylib:arm64e+0x41f0)
    #18 _dispatch_apply_invoke_and_wait <null>:81551592 (libdispatch.dylib:arm64e+0x18f88)
    #19 _dispatch_apply_with_attr_f <null>:81551592 (libdispatch.dylib:arm64e+0x18268)
    #20 dispatch_apply <null>:81551592 (libdispatch.dylib:arm64e+0x18478)
    #21 wrap_dispatch_apply <null>:81551592 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x86488)
    #22 _swift_dispatch_apply_current <null>:81551592 (libswiftDispatch.dylib:arm64e+0x6140)
    #23 static OS_dispatch_queue.concurrentPerform(iterations:execute:) <null>:81551592 (libswiftDispatch.dylib:arm64e+0x5ff4)
    #24 specialized closure #1 in Array.parallelMap<A>(transform:) <null>:81551592 (swiftlint:arm64+0x1000ca5f4)
    #25 specialized Array.parallelCompactMap<A>(transform:) <null>:81551592 (swiftlint:arm64+0x1000c9fdc)
    #26 CollectedLinter.getStyleViolations(using:benchmark:) <null>:81551592 (swiftlint:arm64+0x1000fa32c)
    #27 CollectedLinter.styleViolations(using:) <null>:81551592 (swiftlint:arm64+0x1000fa088)
    #28 (1) suspend resume partial function for closure #1 in static LintOrAnalyzeCommand.collectViolations(builder:) <null>:81551592 (swiftlint:arm64+0x10003bc4c)
    #29 swift::runJobInEstablishedExecutorContext(swift::Job*) <null>:81551592 (libswift_Concurrency.dylib:arm64e+0x3a534)

==89773==Register values:
 x[0] = 0x000000040dbd82d0   x[1] = 0x00000001fefd9d8b   x[2] = 0x0000000000000000   x[3] = 0x000000010000000c  
 x[4] = 0x000000010000000c   x[5] = 0x0000000000000001   x[6] = 0x00000001fefd9a42   x[7] = 0x0000000000000018  
 x[8] = 0x000000010a604478   x[9] = 0x000000010a604478  x[10] = 0x00000001fefd9858  x[11] = 0x0000000000000018  
x[12] = 0x000000000000000c  x[13] = 0x000000020dbd1050  x[14] = 0x00000001b4970000  x[15] = 0x000000040dbd82d0  
x[16] = 0x000000040dbd82d0  x[17] = 0x000000040dbd82d0  x[18] = 0x0000000000000000  x[19] = 0x00000001fefd9d8b  
x[20] = 0x000000010a417240  x[21] = 0x000000020dbd8338  x[22] = 0x00000000000000ec  x[23] = 0x00000000ffdd7f21  
x[24] = 0x000000040dbd82d0  x[25] = 0x0000000000000003  x[26] = 0x000000020aea6070  x[27] = 0x000000016dcc70e0  
x[28] = 0x88fdebadd1ecdc48     fp = 0x000000016dcc5820     lr = 0x00000001b4b22da4     sp = 0x000000016dcc5270  
ThreadSanitizer can not provide additional info.
SUMMARY: ThreadSanitizer: SEGV (libobjc.A.dylib:arm64e+0x79e8) in cache_getImp+0x8
==89773==ABORTING

@jpsim
Copy link
Contributor

jpsim commented Sep 29, 2022

Here's the fork I'm using btw which has Rintaro's original changes applied on top of main: main...jpsim:swift-syntax:fix-data-race

If I may be so bold as to make a suggestion: if you're going to bump the macOS deployment target soon, and the end goal is to move macOS to use os_unfair_lock, just live with the races in older macOS versions in the interim. That's how main currently behaves anyway.

Use mutex to guard concurrent mutation to the arena.

swiftlang#785
rdar://99812330
Passing `os_unfair_lock` with inout expression is considered "mutation"
by thread sanitizer. Instead, keep the lock object with
`let UnsafeMutablePointer` form, and pass it.
@CodaFi CodaFi force-pushed the a-critique-of-pure-reason branch 3 times, most recently from 609d26b to 5b7bdc3 Compare September 30, 2022 04:24
@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 30, 2022

@jpsim Could you try your local tests one last time with this PR?

@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 30, 2022

@swift-ci test

Use pthread_mutex_t on Darwin platforms
Did you know that pthread_mutex_init can _fail_?

On macOS, the value of PTHREAD_MUTEX_INITIALIZER is not just zeroes -
there's optional signature bits in there. POSIX says that you're allowed
to check for those signature bits in the API and issue EINVAL if they
don't match. By default, pthread_mutex_t() in swift will zero-fill
through those signature bits, which results in an invalid mutex
variable - even WRT pthread_mutex_init. Once that fails, all
subsequent calls to lock and unlock will fail too and leave all of
your critical sections completely unguarded.

Thank you POSIX

On Linuxes this is (often) not the case, and they tend to just use zeroes
here, don't check the signature, or both. This allows compilers to allocate
lock variables in .bss, which is kinda neat.

So, on macOS, we need to install those signature bits, BUT Swift cannot
import PTHREAD_MUTEX_INITIALIZER since it's a non-trivial macro that uses
brace initialization. Really what we care about is just the signature bits,
so we'll install those by hand.
@CodaFi CodaFi force-pushed the a-critique-of-pure-reason branch from 5c1aabe to 3dd7635 Compare September 30, 2022 07:45
@CodaFi
Copy link
Contributor Author

CodaFi commented Sep 30, 2022

@swift-ci test

Copy link
Contributor

@jpsim jpsim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Races are gone in my tests, TSan is happy too. 👍

jpsim added a commit to realm/SwiftLint that referenced this pull request Sep 30, 2022
@CodaFi CodaFi merged commit 2a65025 into swiftlang:main Sep 30, 2022
@CodaFi CodaFi deleted the a-critique-of-pure-reason branch September 30, 2022 15:55
jpsim added a commit to realm/SwiftLint that referenced this pull request Sep 30, 2022
jpsim added a commit to realm/SwiftLint that referenced this pull request Sep 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants