swift: XCode 14.2/Swift 5.7 memory corruption on Task creation when app is launched on iOS < 16.
Description Task creation in some contexts can lead to corruption of the application’s memory. Examples can be seen in the demo application code.
Steps to reproduce
- Download demo application source code: https://github.com/mstyura/Swift-Task-Heap-Curruption-on-iOS-15-and-earlier.
- Select scheme
TaskCrasher - Release - libgmalloc - use with arm64 simulator; - Run demo app on
arm64iOS simulator withiOS 15.4;
Expected behavior Application is not crashed.
Actual behavior
Demo app crashes with libgmalloc enabled. Address sanitizer unfortunately unable to catch the issue.

I’ve actually encountered problem on real production application on iOS device where app is randomly crashed on memory access to address 0x100000000 + offset where offset is usually +0x10, +0x20 or -0x8 in application or system library code.
Also in real application libmalloc were capable to detect it was corrupted on some point, but it was unclear who was responsible for corruption.
Environment
- Swift compiler version info
swift-driver version: 1.62.15 Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: arm64-apple-macosx13.0
- Xcode version info
Xcode 14.2
Build version 14C18
- Deployment target: checked that issue happen on iOS 14 and iOS 13 and iOS 15 as deployment target.
Additional context:
An app that I observed crashing worked fine when built with XCode 13.4.1 and Swift 5.6, but experienced significant, random crashes with “bad access” errors on addresses like 0x100000020 when built with XCode 14.2 or XCode 14.1 and Swift 5.7. As a result, it’s currently not feasible to target iOS versions lower than 16 and use Swift 5.7 with async functions and Tasks without encountering random crashes.
UPD: On demo application issue is only happen when compiled with -O (optimize for speed), but not when compiled with -Osize (optimize for size) or -Onone.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 17 (10 by maintainers)
When creating a task, the compiler generates an “initial context size” which tells the runtime how much extra space to allocate. This space is then used for various task-local stuff, like variables that persist across suspension points. The runtime also puts an
AsyncContextat the start of this area. The way it’s supposed to look is:That’s on newer concurrency runtimes, after the commit I linked above. On older concurrency runtimes, it’s supposed to look like this:
However, with a new compiler that thinks
AsyncContextis always smaller, it actually looks like this when running on an older runtime:The
Flagsfield overlaps with what follows, which is, forgive the use of technical jargon, Bad.It looks like this is usually harmless, as the runtime sets
Flagsand then it’s never used again. This happens before any other stuff is written, so that space will be reused and everything works fine. The problem occurs when there is no other stuff. Then you end up with this picture:If nothing else needs to be stored, the compiler asks the runtime to allocate just enough space for
ParentandResumeParent. That means thatFlagspoints off the end of the allocation. If we’re lucky (or running with Guard Malloc),Flagslies in an unmapped page and crashes. If we’re unlucky,Flagslines up with some other random chunk of memory, and smashes whatever happens to be there.I don’t think we need to go so far as to reintroduce
Flags, but we do need to ensure that the compiler reserves enough space for it in the allocation when targeting older OSes.@jasonmolenda thanks for a hint.
~/Library/Logs/DiagnosticReportshad a crash report:Report
Basically swift toolchain has
LLDBwhich attempts to loadPython3.framework, but toolchain is absentPython3.framework. Manually added symlink toXCodesPython3.frameworkto resolve issue:sudo ln -nfs /Applications/Xcode_14.2.app/Contents/Developer/Library/Frameworks/Python3.framework /Library/Developer/Toolchains/swift-5.8-DEVELOPMENT-SNAPSHOT-2023-02-20-a.xctoolchain/System/Library/PrivateFrameworks/Python3.framework. Now I can debug apps with custom swift toolchains. Thanks for a help!@mstyura excellent, thanks for getting to the bottom of it. Ah, I see from the LLDB LC_RPATHs that LLDB looks for the installed Xcode.app as /Applications/Xcode.app to find Python, but you have Xcode installed as Xcode_14.2.app. The Xcode app bundle is normally self contained, but the CommandLineTools lldb has an assumption about the name. I’ll look into what we might be able to do to make this more resilient.
@mstyura Thanks a lot for the nice reproducer. I’m able to replicate the crash here. I’ll see if I can figure out what’s going on.