The introduction of the library providing back-deployment fixes for
Swift 5.6 concurrency libraries (and older) introduced a concurrency
crash in the following OS version ranges
- macOS [12.0, 12.1)
- iOS [15.0, 15.1)
- tvOS [15.0, 15.1)
- watchOS [8.0, 8.2)
Neither older nor newer versions of the listed OSs were affected.
The actual bug involved a miscommunication between the code in the
library that back-deploys fixes (`libswiftCompatibility56.a`) and the
concurrency library in the OS itself. Specifically, the OS versions at
the end of the ranges above introduced voucher support into the
concurrency runtime in the OS (an important feature for performance).
The code in `libswiftCompatibility56.a` that back-ports concurrency fixes
also included the voucher support, which provides a consistent state
for those OS versions and anything newer.
OS versions that predate the introduction of concurrency in the OS are
similarly unaffected, because the embedded
`libswift_Concurrency.dylib` matches that of Swift 5.6, which includes
voucher support.
The OS versions in the affected range include a concurrency library in
the OS that does not manage vouchers. The `libswiftCompatibility56.a`
back-deployed fixes library has code that works on the same data
structures but does manage vouchers, leading to crashes when (say) a
job allocated by the OS version didn't set the "voucher" field, but
the `libswiftCompatibility56.a` tried to free it, essentially a form of
overrelease.
The fix is to teach the voucher-handling code in
`libswiftCompatibility56.a` to first check what version of the OS it
is executing on. If it's in the affected range, all handling of
vouchers is disables so it acts like the concurrency library in the
OS. For both earlier OS versions and later OS versions the
voucher-handler code executes unchanged. This entirely library is
disabled when running on OS versions containing the Swift 5.7
concurrency library (or newer), so those don't need to pay for the
extra check when dealing with vouchers.
Fixes rdar://108837762, rdar://108864311, rdar://108958765.
* Backdeploy swift_task_future_wait
This patch adds the implementation for `swift_task_future_wait`
entrypoint to the backdeploy library.
This involves pulling in `AsyncTask::waitFuture`, which relies on a fair
bit.
Please note, this pulls in the `StaticMutex` implementation from Swift
5.6. There are some challenges here. The concurrency version of the
`StaticMutex` involves a fairly nasty set of ODR violations in the
normal setup. See `public/Concurrency/Mutex.cpp`, which includes the
Mutex implementations cpp files directly, while defining a single macro
to replace the implementation of swift::fatalError with
swift_concurrency_fatalError. We only need the concurrency mutex (at
least for now), so I have hard-coded the `swift_concurrency_fatalError`
version into this library. If we should need the other implementation,
we are forced to include ODR-related undefined behavior.
We need symbols from C++, so I've added an implicit linker flag whenever
the static library is used, namely, it passes `-lc++` to the linker.
Since we only backdeploy on Apple platforms, this should be fine.
Some of the platform runtimes we need to backdeploy to have the
enter/exitThreadLocalContext functions defined, while others don't. We
define our own backdeploy56 shim function that dlsym's the function
pointer for these symbols if we have exclusivity checking available.
Otherwise, it doesn't do anything. If concurrency exclusivity checking
is available, we'll use it, otherwise we wont'.
The same dlsym check is done for `swift_task_escalate`. Not all
platforms we need to backdeploy to have a concurrency runtime. The
symbols that do need to use pieces of the concurrency runtime should not
be getting hit when deploying to systems that don't have concurrency. In
the event that you've gotten around the language blocking you from
calling these symbols and you've managed to call concurrency pieces
without using concurrency, we'll abort because something is seriously
wrong.
* Backdeploy swift_task_future_wait_throwing
Drop the remaining pieces in for adding
`swift_task_future_wait_throwing`.
* Apply task_wait_future fix
Actually apply the fix from ef80a315f8.
This deviates slightly from the original patch.
AsyncTask::PrivateStorage::_Status() does not exist in the Swift 5.6
library. Instead I am using `AsyncTask::PrivateStorage::Status`.
* Workaround missing compiler-rt linking
Working around the missing link against compiler-rt in these test.
They are a bit brittle as if anything in them uses compiler-rt, they
will start failing. The backdeploy 5.6 library uses some symbols from
compiler-rt, thus causes them to fail to link.
Disabling the runtime compatibility version checking to avoid these
symbols. This should be fine for the MicroStdlib test, but we should fix
'%target-ld' to handle this better in the future.
rdar://100868842