Hopefully now it's very easy to fix. Fingers crossed we will have the fix in 13.2.x soon.
What a great Kon & Bal's puzzle page we've got here
SCORING
1-10: There is nothing impossible to they who will try.
10-20: Believe you can and you’re halfway there.
20-30: I swear I am up to no good.
30-40: No, it’s not a Suzuki fans forum!
PS. it's not off-topic, you are just too young.
Also checked with lipo -remove arm64e and it helps! Maybe we can try to make some build phase script which removes arm64e on build as tmp solution.
Added such script into build scheme settings as post action script (need to select your main target in 'Provide build settings from') and now it always work without any additional magic:
FRAMEWORK_EXECUTABLE_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}/Frameworks/libswift_Concurrency.dylib"
if test -f "$FRAMEWORK_EXECUTABLE_PATH"; then
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_PATH"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
fi
Note: need to run this script only if build locally via xcode. I've just also added check if this is debug configuration (as we mostly run debug config via xcode):
if [ ${CONFIGURATION} = "Debug" ]; then
...
fi
Fantastic detective work, Keith!
The fact that DYLD_*
settings on launch affect the result explains why I wasn't able to reproduce; I had something similar set in my OS environment. I'm able to reproduce this on iOS 14 now, and can confirm that removing the arm64e slice addresses the issue.
Doug
It turns out dyld_info
also surfaces this error in its output, although interestingly it still exits with a 0:
% dyld_info DerivedData/CrashTest2/Build/Products/Debug-iphoneos/CrashTest2.app/Frameworks/libswift_Concurrency.dylib
DerivedData/CrashTest2/Build/Products/Debug-iphoneos/CrashTest2.app/Frameworks/libswift_Concurrency.dylib [arm64]:
-platform:
platform minOS sdk
iOS 13.0 15.2
-segments:
load-offset segment section sect-size seg-size perm
0x00000000 __TEXT 256KB r.x
0x000076F4 __text 187908
0x000354F8 __stubs 2028
0x00035CE4 __stub_helper 2028
0x000364D0 __const 10931
0x00038F90 __cstring 4918
0x0003A2C6 __swift5_typeref 1677
0x0003A954 __swift5_capture 388
0x0003AAE0 __swift5_reflstr 467
0x0003ACB4 __swift5_assocty 1056
0x0003B0D4 __swift5_fieldmd 2764
0x0003BBA0 __swift5_builtin 80
0x0003BBF0 __swift5_protos 24
0x0003BC08 __swift5_proto 212
0x0003BCDC __swift5_types 280
0x0003BDF4 __objc_methname 241
0x0003BEE5 __objc_classname 20
0x0003BEF9 __objc_methtype 412
0x0003C095 __info_plist 591
0x0003C2E4 __unwind_info 5640
0x0003D8F0 __eh_frame 10000
0x00040000 __DATA_CONST 16KB rw.
0x00040000 __got 248
0x000400F8 __mod_init_func 8
0x00040100 __const 7080
0x00041CA8 __objc_classlist 40
0x00041CD0 __objc_imageinfo 8
0x00044000 __DATA 32KB rw.
0x00044000 __la_symbol_ptr 1352
0x00044548 __objc_const 1312
0x00044A68 __objc_selrefs 8
0x00044A70 __objc_superrefs 8
0x00044A78 __objc_ivar 4
0x00044A80 __objc_data 80
0x00044AD0 __data 2152
0x00045340 __bss 15280
0x00048EF0 __common 56
-dependents:
attributes load path
/usr/lib/libobjc.A.dylib
/usr/lib/libc++.1.dylib
/usr/lib/libSystem.B.dylib
/usr/lib/swift/libswiftCore.dylib
dyld_info: 'DerivedData/CrashTest2/Build/Products/Debug-iphoneos/CrashTest2.app/Frameworks/libswift_Concurrency.dylib' chained fixups, seg_count exceeds number of segments
It looks like part of the problem is that the chained fixups seg_count is 5, which corresponds to:
chained starts in image
seg_count = 5
seg_offset[0] = 0 (__TEXT)
seg_offset[1] = 24 (__DATA_CONST)
seg_offset[2] = 48 (__DATA)
seg_offset[3] = 0 (__LLVM)
seg_offset[4] = 0 (__LINKEDIT)
But then when you build your app, Xcode appears to strip bitcode from the dylib (since it isn't used by default in debug mode), but the fixups seg_count remains 5, so the output from otool actually appears to overflow and show something that's no a segment in its previous place:
chained starts in image
seg_count = 5
seg_offset[0] = 0 (__TEXT)
seg_offset[1] = 24 (__DATA_CONST)
seg_offset[2] = 48 (__DATA)
seg_offset[3] = 0 (__LINKEDIT)
seg_offset[4] = 0 (libobjc)
Interestingly if I set the undocumented BITCODE_GENERATION_MODE=bitcode
build setting to force bitcode even in debug mode, the dylib still contains bitcode so it gets past the original issue, but I get a different crash still in dyld.
Amazing work @Keith and thanks for finding the issue and providing more information.
@Douglas_Gregor / @zavsby / @Keith - I am wondering how does these findings gets into Xcode as a stable resolution, that we can use in production? I am aware of the excellent build phase script Sergey has put together but we would prefer to avoid workarounds. Any thoughts?
Ah, interesting. And running lipo -remove arm64e
corrects the problem. This may be the reason why iOS is refusing to load libswift_Concurrency.dylib
.
I'm curious about this different crash you're seeing. For me, setting BITCODE_GENERATION_MODE=bitcode
in the build settings worked around the issue.
This cannot be addressed without a new Xcode release, and we (== those of us that work at Apple, like myself) cannot tell you when that will be. The issue is tracked by FB9780976, and we're looking into fixing it.
The build phase script is likely the safest workaround for now.
Doug
Assuming that you're targeting iOS 13+ shouldn't the binary link libswift_Concurrency
not weakly? I noticed some of the other swift libraries are also weak like this that I assume could also not be since they are also required?
Interesting, I had assumed it would as well, but with just that change (like this Comparing main...bitcode-mode · keith/backdeploy-concurrency-crash · GitHub) I see this crash on my iOS 13 device:
* thread #1, stop reason = EXC_BAD_ACCESS (code=1, address=0x1831de43c)
* frame #0: 0x000000010235dd78 dyld`dyld3::MachOAnalyzer::forEachObjCMethod(unsigned long long, bool, void (unsigned long long, dyld3::MachOAnalyzer::ObjCMethod const&) block_pointer) const + 224
frame #1: 0x000000010235d128 dyld`invocation function for block in dyld3::MachOAnalyzer::forEachObjCClass(Diagnostics&, bool, void (Diagnostics&, unsigned long long, unsigned long long, unsigned long long, dyld3::MachOAnalyzer::ObjCClassInfo const&, bool) block_pointer) const + 504
frame #2: 0x0000000102353a2c dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 544
frame #3: 0x0000000102352c4c dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 168
frame #4: 0x00000001023537c4 dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 180
frame #5: 0x000000010235cf14 dyld`dyld3::MachOAnalyzer::forEachObjCClass(Diagnostics&, bool, void (Diagnostics&, unsigned long long, unsigned long long, unsigned long long, dyld3::MachOAnalyzer::ObjCClassInfo const&, bool) block_pointer) const + 204
frame #6: 0x000000010236a5a8 dyld`dyld3::closure::ClosureBuilder::optimizeObjCSelectors(objc_opt::objc_selopt_t const*, dyld3::Map<char const*, dyld3::closure::Image::ObjCImageOffset, dyld3::closure::ClosureBuilder::HashCString, dyld3::closure::ClosureBuilder::EqualCString> const&, dyld3::closure::ClosureBuilder::ObjCOptimizerImage&) + 588
frame #7: 0x00000001023691e0 dyld`dyld3::closure::ClosureBuilder::optimizeObjC(dyld3::Array<dyld3::closure::ImageWriter>&) + 876
frame #8: 0x000000010236d364 dyld`dyld3::closure::ClosureBuilder::makeLaunchClosure(dyld3::closure::LoadedFileInfo const&, bool) + 1176
frame #9: 0x0000000102333f1c dyld`dyld::buildLaunchClosure(unsigned char const*, dyld3::closure::LoadedFileInfo const&, char const**) + 368
frame #10: 0x0000000102332b0c dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 2844
frame #11: 0x000000010232d22c dyld`dyldbootstrap::start(dyld3::MachOLoaded const*, int, char const**, dyld3::MachOLoaded const*, unsigned long*) + 432
frame #12: 0x000000010232d038 dyld`_dyld_start + 56
The details from the device are similarly slim:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x000000018391243c
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [650]
Highlighted by Thread: 0
Backtrace not available
Unknown thread crashed with ARM Thread State (64-bit):
x0: 0x000000016d609d50 x1: 0x0000000000000008 x2: 0x0000000000000000 x3: 0x0000000000000000
x4: 0x000000016d609d20 x5: 0x0000000000000000 x6: 0x7366657272657075 x7: 0x0000000000000d60
x8: 0x000000008000000c x9: 0x000000016d609e93 x10: 0x0000000000046430 x11: 0x0000000000000004
x12: 0x0000000000ff0006 x13: 0x0000000000048000 x14: 0x0000000000000000 x15: 0x0000000102b8c018
x16: 0xfffffffffffffff6 x17: 0x0000000102a858d4 x18: 0x0000000000000000 x19: 0x000000016d609e3b
x20: 0x0000000000000000 x21: 0x00000001038cc000 x22: 0x0000000000000000 x23: 0x0000000000000001
x24: 0x000000008004643c x25: 0x0000000000000001 x26: 0x000000016d609e93 x27: 0x0000000103912428
x28: 0x000000018391243c fp: 0x000000016d609ef0 lr: 0x0605290102a91e24
sp: 0x000000016d609db0 pc: 0x0000000102a91d78 cpsr: 0x80000000
esr: 0x00000000 Address size fault
Binary images description not available
Error Formulating Crash Report:
Failed to create CSSymbolicatorRef - corpse still valid ¯\_(ツ)_/¯
EOF
@Douglas_Gregor Makes sense! We will try the scripts in the meantime and will report back if we find any issues. Thanks!
It was intentional. There are is an unfortunate configuration where folks build binaries that use concurrency on iOS 15/macOS 12+ but deploy earlier and aren't app bundles (e.g., a command-line utility that's not within an app bundle). Non-weak linkage breaks these programs on launch; weak linkage allows them to continue to work so long as they are careful not to actually use concurrency on older OS versions. Aside from a small launch-time cost on older OS versions, using weak linking here doesn't hurt.
I'm not seeing this crash on iOS 14, perhaps because iOS 13 isn't expecting to see bitcode at all. It implies that BITCODE_GENERATION_MODE=bitcode
isn't a viable workaround for everyone. The script that lipo
's out the arm64e slice seems to be the best workaround for now.
Doug
I wonder for this case if it would also be better to strongly link the framework, given that folks who don't understand the inner workings of copying dylibs might not know about this, and hope to target older OS versions and have this "just work", IMO it might actually be nice to be explicit about having them weak link the target, but I also understand that less configuration can be nicer in some cases.
Either way my only thought is maybe this issue would have been caught sooner if it wasn't weakly linked, but I'm glad we found a resolution, thanks everyone!
This crash seems to occur only with debug build runs from Home Screen. To test this theory, I tested the code without build script provided by Sergey, in Adhoc and Test Flight build and it did not crash.
Could you guys explain why it is crashing only for debug build run from Home Screen? What is the difference between debug build from Xcode and run from Home Screen? Thanks!
This appears to be the same issue I ran into last month here — Using actor in iOS 14 crashes on initialization using Xcode 13.2
I can confirm that my app works when run initially from Xcode, but terminating the app and relaunching from the Home Screen crashes with the same 0x0000000000000000
EXC_BAD_ACCESS
error.
It seems like the issue is reproducible / others are experiencing the problem now but I'm happy to help with any debugging as well.
When running from Xcode, some DYLD environment variables are automatically set, which force the process to load the arm64 slice rather than failing to load the shared library. As Keith showed, unchecking all of the options in the scheme that map to DYLD environment variables (eg, Main Thread Checker) will result in the program crashing on launch from Xcode as well.
Doug
Makes sense and thank you very much @Douglas_Gregor . I know you already answered this question but going to ask again :) Any thoughts when a new Xcode version resolving this issue would be released? Just a ball park, One week, one month?
Jay Muthialu
(post deleted by author)
Release builds (build with Xcode in release mode and then launch the app from the home screen) are also affected exactly the same way.
Is this a blocker for you? I downgraded to Xcode 13.1 because of this issue, but maybe I'm alright with that only because I don't need something new/fancy that's only available in Xcode 13.2.
Correct. Anything via Xcode.
Is this a blocker for you?
Not a hard blocker. We are upgrading to new concurrency APIs which we love very much (thanks Apple team). I have tested with the script provided by @zavsby and it works great. But we are bit cautious and we would prefer to go with a resolution through Xcode version bump. If that takes lot of time then we would go with the script.
Many many thanks for all the contributors here to help debug the issue very quickly and provide a workaround. Thank you all so so much!!
Jay Muthialu