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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions