Skip to content

Add more robust signal processing #3

@eonist

Description

@eonist
import Foundation
import Darwin

public class Crashlytic {
    // Existing properties and methods...

    /**
     * Set up the crash handler
     */
    public func setUpCrashHandler() {
        #if DEBUG
        if isDebug { Swift.print("setUpCrashHandler") }
        #endif

        // Prepare signal action
        var sigAction = sigaction()
        sigAction.sa_flags = SA_SIGINFO
        sigAction.__sigaction_u = unsafeBitCast(handleSignal as (@convention(c) (Int32, UnsafeMutablePointer<siginfo_t>?, UnsafeMutableRawPointer?) -> Void)!, to: __sigaction_u.self)

        // Register signal handlers
        sigaction(SIGABRT, &sigAction, nil)
        sigaction(SIGILL,  &sigAction, nil)
        sigaction(SIGSEGV, &sigAction, nil)
        sigaction(SIGFPE,  &sigAction, nil)
        sigaction(SIGBUS,  &sigAction, nil)
        sigaction(SIGPIPE, &sigAction, nil)
    }

    /**
     * Signal handler function
     */
    private func handleSignal(signal: Int32, info: UnsafeMutablePointer<siginfo_t>?, context: UnsafeMutableRawPointer?) {
        var crashDetails: [String: String] = [:]
        crashDetails["Signal"] = "\(signal)"

        if let code = info?.pointee.si_code {
            crashDetails["SignalCode"] = "\(code)"
        }
        if let address = info?.pointee.si_addr {
            crashDetails["FaultAddress"] = "\(address)"
        }

        // Attempt to capture stack trace
        captureStackTrace(into: &crashDetails)

        // Save the crash report
        saveCrashReport(crashDetails)

        // Re-raise the signal with default handler to terminate the app
        signal(signal, SIG_DFL)
        raise(signal)
    }

    /**
     * Capture the stack trace
     */
    private func captureStackTrace(into crashDetails: inout [String: String]) {
        var stack = [UInt](
            repeating: 0,
            count: 128
        )
        let stackSize = stack.count
        let frameCount = stack.withUnsafeMutableBufferPointer { buffer -> Int in
            return backtrace(UnsafeMutablePointer(mutating: buffer.baseAddress), Int32(stackSize))
        }
        if let symbols = backtrace_symbols(UnsafeMutablePointer(mutating: stack), Int32(frameCount)) {
            var stackTrace = ""
            for i in 0..<Int(frameCount) {
                if let symbol = symbols[i] {
                    stackTrace.append(String(cString: symbol))
                    stackTrace.append("\n")
                }
            }
            crashDetails["StackTrace"] = stackTrace
            free(symbols)
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions