Unexplainable Swift EXC_BREAKPOINT Crash - ios

consider the following code:
#objc public func endAllSessionsWithReason(_ reason: Reason, completion completionBlock: (() -> Void)?) {
let allActiveSessions = self.activeSessions.map({$0.value})
for session in allActiveSessions {
if (reason != .undetermined) {
session.reason = reason
}
self.endSession(session, deleteSession: false)
}
let allActiveSessionIds = allActiveSessions.map({$0.sessionId})
self.deleteSessionsWithIds(sessionIds: allActiveSessionIds, completion: completionBlock)
}
Crashlytics is reporting the following crash in this code:
Crashed: com.apple.main-thread
EXC_BREAKPOINT 0x0000000103032788
SessionController.swift line 183
specialized SessionController.endAllSessionsWithReason(_:completion:)
where line 183 refers to:
let allActiveSessionIds = allActiveSessions.map({$0.sessionId})
I've tried figuring out what could cause this crash for a few days now, and haven't been able to reproduce it. I don't see any implicit unwraps or optionals here, but sessionId is a non-optional value in the session object if that matters.
self.activeSessions is a non-optional value as well, but can be empty.
I am using swift 4.1, and the crashes occur on on iOS devices running all the different flavors of iOS 10, 11, and 12. The app does support some builds of iOS 9, but none have been reported (although that may be irrelevant because the iOS 9 user base for the app is extremely small).

Related

Swift: Enums with stored properties not thread safe even when mutated using a serial queue

This issue relates to another issue reported on the Apple Developer forum titled How to avoid Data Races in deinit from 4 years ago. I am seeing crashes in production related to associated data and outlined consume code added by the compiler to deinitialize enums with associated data that contain reference types.
When trying to find if someone else has faced the same issue, I stumbled across the above post. I reduced the example from that post to a simpler example below and reliably get a crash due to bad access. (I ran this in Playground and got the crash but no stack trace)
import Foundation
class Racer {
let queue = DispatchQueue(label: "Racer-\(UUID())")
var value: String? = "" // Desugars to Optional<String>, an enum
func race() {
queue.async {[weak self] in
self?.value = UUID().uuidString
}
}
}
let racer = Racer()
while true {
racer.race()
}
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x357d20cc94c0).
Is this a bug in Swift that has yet to be patched?

Firebase crashlytics does not telling me the exact crash problem with swift

I've already read a lot of questions about this on stack, but is there any solution to fix this to get the missing part of the crashreport?
I understand that these crashes were caused by some reason of nil or unwrapped options or something else, but crashes from objc are much better:
My project is based on objetive-c (started a few years ago) but the new big parts are written in swift. All crashes which are coming from the objc part are well detailed but those which are coming from the swift part not.
So the question is, how will I get readable crash reports instead of EXC_BREAKPOINT 0x00000001028817ac
For such cases, I would recommend adding advanced analytics of user behavior in the app and then try to repeat the same steps as the user. This will help to find the root of such crashes. I can share the code on the foundation of which you may add the necessary functionality on the screens of your app:
import Foundation
import Crashlytics
class EventLogger {
/// Log a handled non-fatal exception
class func logException(_ exception: NSException) {
print("Catched exception: \(exception.debugDescription)")
let frames = exception.callStackSymbols.map { symbol in CLSStackFrame(symbol: symbol) }
Crashlytics.sharedInstance().recordCustomExceptionName(exception.name.rawValue, reason: exception.reason, frameArray: frames)
}
private class func log(_ string: String) {
CLSLogv(string, getVaList([]))
}
class func log(screen: String) {
log("User is located at \(screen) Screen")
}
/// Log a status of feature
class func log(feature: String, status: String) {
log("Feature \(feature) was \(status)")
}
/// Log an event
class func log(event: String) {
log("Event: \(event)")
}
}
and impement it like here:
EventLogger.log(event: "Pressed login button")
After the crash, you can see the action log exactly for this crash

iOS app installed form TestFlight behaves different from that is installed directed from Xcode

Recently I created a scientific calculator app, and everything was fine when I installed it from Xcode and tested it directly on my phone. However, after I installed the version that I distributed it through Testflight(it is exactly same as the one before), the app start crush every second time when an IBOAction is called(the sender is UIPanGestureRecognizer). Initially it shows NSInvalidArgumentException message, and I find the line
if sender.state == .began
might cause the error.
However, after a few tests, it starts showing
"Thread 1: EXC_BAD_ACCESS (code=1, address=0x6c43f8bb8e00)" (at the line "init(elementKeeper: ElementKeeper)")
instead of
NSInvalidArgumentException
I have no idea what is happening here. Someone please helps me, I will appreciate it.
public class ParentheseKeeper {
private var leftParenthese: [Int]
private var rightParenthese: [Int]
// MARK:- Initialization
init() {
leftParenthese = []
rightParenthese = []
}
init(elementKeeper: ElementKeeper) { //"Thread 1: EXC_BAD_ACCESS (code=1, address=0x6c43f8bb8e00)" shows here
leftParenthese = []
rightParenthese = []
for (i, element) in elementKeeper.getElements().enumerated() {
if element == .LeftParenthese { addLeft(i) }
else if element == .RightParenthese { addRight(i) }
}
}
}

How to log a warning that shows up as a runtime issue in Xcode?

Xcode 8 or 9 started displaying runtime issues. You see a purple icon at the top of the window, and a list in Issue Navigator, next to buildtime issues like compilation warnings and errors.
The runtime issues I've seen are created by the system libraries. Is there a way for my own application code to generate these?
Yes! You'll see these if you do something that a sanitizer catches, like performing certain UI operations a background thread with Thread Sanitizer enabled. Having an ambiguous layout and pausing in the view debugger is also a way to get this to occur. Either way, seeing this occur in Apple's libraries isn't a good thing…
UPDATE: I looked into how these warnings are hit, and LLDB essentially sets a breakpoint on a set of magic functions (__asan::AsanDie(), __tsan_on_report, __ubsan_on_report, __main_thread_checker_on_report) inside of a sanitizer dynamic library that are called when issues occur. If you define your own version of these functions and call them, you'll get the warning to show up. First, create the symbol somewhere in your project:
void __main_thread_checker_on_report(char *message) {
}
Then you can trigger it at will, just by putting this code anywhere in your application (you probably want to hide it behind a macro):
((void (*)(char *))dlsym(dlopen(NULL, RTLD_LAZY), "__main_thread_checker_on_report")))("This will show up as a warning")
Needless to say, this will almost certainly not play nicely with the actual sanitizer if you choose to use it. You should probably compile the above conditionally based on whether you are using a sanitizer or not.
In XCode 8.3 and earlier you can use set breakpoint into any method of UIKit class like setNeedsDisplay() like below.
Also there is library in objective-c steipete class in which #import <objc/runtime.h> is used.
But in Xcode 9 below library Xcode.app/Contenets/Developer/usr/lib/libMainThreadChecker.dylib is available, Which handle for any relevant issues potentially performed out-of-main thread at runtime.
Well, that's a hack, far from ideal, but can by useful to get runtime warnings without having game-over behavior like in assertions or fatal errors:
func runtimeWarning(_ message: String, file: String = #file, line: Int = #line) {
#if DEBUG
DispatchQueue.global(qos: .userInteractive).async {
// If you got here, please check console for more info
_ = UIApplication.shared.windows
print("Runtime warning: \(message): file \(file.fileName), line \(line)")
}
#endif
}
fileprivate extension String {
var fileName: String { URL(fileURLWithPath: self).lastPathComponent }
}
Unfortunately this leads to quite a big print to console from Main Thread Checker, also does not show on correct line, but at least you have all info needed in console (including line of code you should check).
Usage and result is very similar to assertionFailure or fatalError:
runtimeWarning("Hi, I'm purple")
leads to message in console:
Runtime warning: Hi, I'm purple: file MyFile.swift, line 10
and this, so you won't miss it:
Just wanted to add a Swift implementation of a runtimeWarning method, for anyone curious:
func runtimeWarning(_ message: String) {
// Load the dynamic library.
guard let handle = dlopen(nil, RTLD_NOW) else {
fatalError("Couldn't find dynamic library for runtime warning.")
}
// Get the "__main_thread_checker_on_report" symbol from the handle.
guard let sym = dlsym(handle, "__main_thread_checker_on_report") else {
fatalError("Couldn't find function for runtime warning reporting.")
}
// Cast the symbol to a callable Swift function type.
typealias ReporterFunction = #convention(c) (UnsafePointer<Int8>) -> Void
let reporter = unsafeBitCast(sym, to: ReporterFunction.self)
// Convert the message to a pointer
message.withCString { messagePointer in
// Call the reporter with the acquired messagePointer
reporter(messagePointer)
}
}
CocoaLumberjack framework can be used to capture Run times console logs as well as App's Background wakeup logs.
https://github.com/CocoaLumberjack/CocoaLumberjack
https://github.com/phonegap/phonegap-plugin-push/issues/1988
This way you can capture purple warnings displayed in Xcode9 like below in a file that is maintained inside App Container:-
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication registerUserNotificationSettings:]
PID: 2897, TID: 1262426, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 21
It depends on you if you are doing any UI related stuff on other then main thread so system will generate for you else you can not manually generate it.
All UI manipulations should be done in the Main Thread.
If you are not doing this so, in XCode 9 have feature called Main thread checker.
For more info, you can visit below url: https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
It is basically used to checks whether any UIKit related stuff is happening on a main thread or not ?, If failed to do so, it will produce issues at Runtime. So wrap your code in Main Thread block like below to avoid glitches and runtime warnings.
You can Enable - Disable using this steps Edit Scheme... -> (Select your scheme) -> Diagnostics -> Disable 'Main thread checker'
Swift Composable Architecture folks dug into this and found a solution
You should read about it here
And you can get the code here
which you can then use as
runtimeWarning("This is neat")
full code because SO likes code rather than references:
#if DEBUG
import os
import XCTestDynamicOverlay
// NB: Xcode runtime warnings offer a much better experience than traditional assertions and
// breakpoints, but Apple provides no means of creating custom runtime warnings ourselves.
// To work around this, we hook into SwiftUI's runtime issue delivery mechanism, instead.
//
// Feedback filed: https://gist.github.com/stephencelis/a8d06383ed6ccde3e5ef5d1b3ad52bbc
private let rw = (
dso: { () -> UnsafeMutableRawPointer in
let count = _dyld_image_count()
for i in 0..<count {
if let name = _dyld_get_image_name(i) {
let swiftString = String(cString: name)
if swiftString.hasSuffix("/SwiftUI") {
if let header = _dyld_get_image_header(i) {
return UnsafeMutableRawPointer(mutating: UnsafeRawPointer(header))
}
}
}
}
return UnsafeMutableRawPointer(mutating: #dsohandle)
}(),
log: OSLog(subsystem: "com.apple.runtime-issues", category: "ComposableArchitecture")
)
#endif
#_transparent
#inline(__always)
func runtimeWarning(
_ message: #autoclosure () -> StaticString,
_ args: #autoclosure () -> [CVarArg] = []
) {
#if DEBUG
let message = message()
unsafeBitCast(
os_log as (OSLogType, UnsafeRawPointer, OSLog, StaticString, CVarArg...) -> Void,
to: ((OSLogType, UnsafeRawPointer, OSLog, StaticString, [CVarArg]) -> Void).self
)(.fault, rw.dso, rw.log, message, args())
XCTFail(String(format: "\(message)", arguments: args()))
#endif
}
code is MIT licenced

Force reload watchOS 2 Complications

I have issues getting Complications to work. It would be helpful if I was able to reliably refresh them.
Therefore I linked a force-press menu button to the following method
#IBAction func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications {
complicationServer.reloadTimelineForComplication(complication)
}
}
Unfortunately this leads to the app crashing. with a fatal error: unexpectedly found nil while unwrapping an Optional value.
I understand that calling reloadTimelineForComplication(complication) is budgeted but that can't be the issue here as it doesn't work from the very beginning.
I am currently using watchOS2 + Xcode 7 GM
I'd appreciate any ideas on making Complications refresh while the app is running?
Trace or use the exception breakpoint and focus on reading the whole error message where it tells you exactly on which line it found the nil unexpectedly (I do suspect the complicationServer). Use 'if let' instead of 'let' to force unwrap the respective variable.
private func reloadComplications() {
if let complications: [CLKComplication] = CLKComplicationServer.sharedInstance().activeComplications {
if complications.count > 0 {
for complication in complications {
CLKComplicationServer.sharedInstance().reloadTimelineForComplication(complication)
NSLog("Reloading complication \(complication.description)...")
}
WKInterfaceDevice.currentDevice().playHaptic(WKHapticType.Click) // haptic only for debugging
}
}
}

Resources