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
[SR-7493] EXC_BAD_ACCESS of NSError via caught error.localizedDescription, only in Archive builds! #50036
Comments
Strange! I have no ideas offhand. If you can share your full project, one option would be to file an Apple bug report (radar) and attach the project so we can try to reproduce the issue. Otherwise, unless someone happens to recognize this as a known issue, I'm not sure we can help you. |
Comment by Nathan Vander Wilt (JIRA) Thanks Bob. After a bit more wrangling it turns out this is really simple to reproduce, fortunately! The issue stems from the error instance. I was trying unsuccessfully to reproduce with a Swift error, but it turns out the error was bubbling up from lower down, presumably an NSError. 1. Put this in main.swift of a new Xcode 9.3 (9E145)'s macOS "Command Line Tool" project template: import Foundation
do {
_ = try Data(contentsOf: URL(fileURLWithPath: "/tmp/not/exist/file/missing"))
} catch {
NSLog("About to access `error.localizedDescription`")
print(error.localizedDescription)
NSLog("Done. No crash.")
} 2. Product > Run — all three lines will be output, finishing with "Done. No crash." as expected 3. Product > Archive — run the executable inside the Archive directly from terminal or via lldb. It will log "About to access" and then… Segmentation fault: 11 |
Comment by Nathan Vander Wilt (JIRA) Tested against Xcode 9.2 / Swift 4.0 and same behavior:
Again the only non-path difference I've been able to spot so far is that in the Archive build some extra
flags are seen in the build log. |
Comment by Nathan Vander Wilt (JIRA) Attached a sample (back in Xcode 9.3 again) project. This is a significant blocker for my client, since our packaging process is based around Archive builds: Everything works fine when testing, but randomly "explodes" when deployed! |
@swift-ci create |
Thanks, Nathan. We'll investigate. |
Comment by Simon Corsin (JIRA) I also encountered the same exact issue. On release and debug through Xcode it works, after archiving it crashes. A workaround that works for me natevw (JIRA User) is to explicitly mark the error as NSError: do {
// some code that can throw
} catch let error as NSError {
let errorMessage = error.localizedDescription
} If I don't it will crash at runtime when calling localizedDescription. The underlying error in that case is an NSError that comes from Objective-C code |
Comment by Nathan Vander Wilt (JIRA) Thanks for the confirmation Simon! I'm still hoping for more of a "build settings"–level workaround but if worse comes to worse we might have to add something like that to all our catch blocks for the time being. |
Comment by Nathan Vander Wilt (JIRA) Figured out the difference! Archive build is calling /usr/bin/strip, which the Release build doesn't do. Confirmed that if I build a Debug/Release build and then call strip on the resulting product it exhibits the same behavior. Thus a workaround for this issue is to set STRIP_INSTALLED_PRODUCT = NO (i.e. in Build Settings, in the Deployment section, set "Strip Linked Product" to No). I see there are other settings "Strip Style" and "Strip Swift Symbols" that may provide a more fine-grained workaround but haven't experimented with those yet. UPDATE Turning off STRIP_SWIFT_SYMBOLS has no effect, however setting STRIP_STYLE to either 'non-global' or 'debugging' (anything but the default 'all') does prevent the segfault without having to turn STRIP_INSTALLED_PRODUCT off entirely. UPDATE #2 Leaving all other Deployment configuration alone and setting "STRIPFLAGS = -u" also avoids the segfault. This is documented in `man 1 strip` as meaning: > Save all undefined symbols. This is intended for use with relocatable objects to save symbols referred to by external relocation entries. A few other promising options (e.g. -r to "Save all symbols referenced dynamically") only caused the strip command to become upset. It might be possible to specifically whitelist a few symbols using -s to pass a list file. But I'm neither sure what the symbol for the Error/NSError localizedDescription would be nor whether that symbol is the only problematic one or merely the first noticed. |
This has been fixed in #16677 I changed the symbol lookup mechanism to add a bit of indirection and marked the new indirect symbols as dynamically referenced, which preserves them when stripping. To work around it until you're able to use that, you can find the symbols to whitelist in
(Depending on how far you go back, there may be a different prefix on the names. You can check your unstripped binary with Or, of course, skipping the strip phase is a simple way to get it working for now. |
Attachment: Download
Additional Detail from JIRA
md5: b1e28c85954878764a8d6b92b44b49d5
Issue Description:
I have a vexing issue with my production builds under Xcode 9.3 (9E145).
In a certain catch blocks, calls to `error.localizedString` crash in Archive builds:
When I run (Debug configuration) from Xcode there is no issue, nor even when I edit the scheme to use Release configuration for the Run action.
When I "Archive" the product the issue is encountered — even when turning off Swift Compiler and LLVM optimization settings!
I took some time to try parse through the differences in swiftc compiler and clang linker commands between the two builds. There didn't appear any swiftc difference, only an extra bit about "-Xlinker -final_output -Xlinker MyTarget" in the clang linker call.
Unfortunately I have not been able to reduce this in a sample project but after updating to Xcode 9.3 it is happening reliably for this target's Archive builds.
The text was updated successfully, but these errors were encountered: