From 55dbab498fda96c135b37c88704d04c75b487348 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Thu, 4 Oct 2018 15:26:18 +0200 Subject: [PATCH] recover from exception on iOS and macOS using signals and log the stacktrace --- PanoPainter-OSX/main.cpp | 31 ++---------------- PanoPainter.xcodeproj/project.pbxproj | 12 +++---- PanoPainter/AppDelegate.m | 18 ----------- PanoPainter/{main.m => main.cpp} | 2 ++ src/objc_utils.cpp | 45 +++++++++++++++++++++++++-- src/objc_utils.h | 6 ++-- src/pch.h | 3 -- 7 files changed, 53 insertions(+), 64 deletions(-) rename PanoPainter/{main.m => main.cpp} (86%) diff --git a/PanoPainter-OSX/main.cpp b/PanoPainter-OSX/main.cpp index 91a1b11..5796221 100644 --- a/PanoPainter-OSX/main.cpp +++ b/PanoPainter-OSX/main.cpp @@ -19,32 +19,6 @@ std::deque> tasklist; std::mutex task_mutex; -void global_exception_handler(NSException* e) -{ - NSAlert *alert = [NSAlert alertWithMessageText:@"Recovery" - defaultButton:@"OK" alternateButton:@"Cancel" - otherButton:nil informativeTextWithFormat:@"Exception"]; - [alert runModal]; - - if (App::I.canvas && App::I.canvas->m_canvas) - App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); - - std::terminate(); -} - -void global_signal_handler(int e) -{ - NSAlert *alert = [NSAlert alertWithMessageText:@"Recovery" - defaultButton:@"OK" alternateButton:@"Cancel" - otherButton:nil informativeTextWithFormat:@"Signal"]; - [alert runModal]; - - if (App::I.canvas && App::I.canvas->m_canvas) - App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); - - std::terminate(); -} - @implementation View - (void)async_lock { @@ -451,6 +425,8 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime } - (void)applicationDidFinishLaunching:(NSNotification *)notification { + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }]; + if (!App::I.check_license()) return; @@ -492,9 +468,8 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime int main(int argc, const char * argv[]) { + install_global_handlers(); AppOSX* app = [AppOSX sharedApplication]; - NSSetUncaughtExceptionHandler(&global_exception_handler); - signal(SIGFPE, global_signal_handler); [app run]; return 0; } diff --git a/PanoPainter.xcodeproj/project.pbxproj b/PanoPainter.xcodeproj/project.pbxproj index 03b209d..f55ddab 100644 --- a/PanoPainter.xcodeproj/project.pbxproj +++ b/PanoPainter.xcodeproj/project.pbxproj @@ -137,7 +137,7 @@ ADC6F4681F3E66FB004177FA /* app_dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADC6F4651F3E66FA004177FA /* app_dialogs.cpp */; }; ADD6AFD71F94DEB000E92461 /* node_progress_bar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADD6AFD61F94DEAF00E92461 /* node_progress_bar.cpp */; }; ADD6AFD81F94DEB000E92461 /* node_progress_bar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADD6AFD61F94DEAF00E92461 /* node_progress_bar.cpp */; }; - ADD7D26F1EBF9AE300D5A897 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D26E1EBF9AE300D5A897 /* main.m */; }; + ADD7D26F1EBF9AE300D5A897 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D26E1EBF9AE300D5A897 /* main.cpp */; }; ADD7D2721EBF9AE300D5A897 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */; }; ADD7D2791EBF9AE300D5A897 /* GameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD7D2781EBF9AE300D5A897 /* GameViewController.m */; }; ADD7D27C1EBF9AE300D5A897 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADD7D27A1EBF9AE300D5A897 /* Main.storyboard */; }; @@ -397,7 +397,7 @@ ADD6AFD51F94DEAF00E92461 /* node_progress_bar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = node_progress_bar.h; sourceTree = ""; }; ADD6AFD61F94DEAF00E92461 /* node_progress_bar.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = node_progress_bar.cpp; sourceTree = ""; }; ADD7D26B1EBF9AE300D5A897 /* PanoPainter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanoPainter.app; sourceTree = BUILT_PRODUCTS_DIR; }; - ADD7D26E1EBF9AE300D5A897 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + ADD7D26E1EBF9AE300D5A897 /* main.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = main.cpp; sourceTree = ""; }; ADD7D2701EBF9AE300D5A897 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; ADD7D2711EBF9AE300D5A897 /* AppDelegate.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = AppDelegate.m; sourceTree = ""; }; ADD7D2771EBF9AE300D5A897 /* GameViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameViewController.h; sourceTree = ""; }; @@ -781,7 +781,7 @@ children = ( ADEBA9082069A50E0085AE16 /* objc_utils.cpp */, ADEBA9072069A50E0085AE16 /* objc_utils.h */, - ADD7D26E1EBF9AE300D5A897 /* main.m */, + ADD7D26E1EBF9AE300D5A897 /* main.cpp */, ); name = "Supporting Files"; sourceTree = ""; @@ -1250,7 +1250,7 @@ ADD7D2A21EBF9E1C00D5A897 /* util.cpp in Sources */, ADD7D2791EBF9AE300D5A897 /* GameViewController.m in Sources */, AD4CEF142156B2C60097F4BD /* node_about.cpp in Sources */, - ADD7D26F1EBF9AE300D5A897 /* main.m in Sources */, + ADD7D26F1EBF9AE300D5A897 /* main.cpp in Sources */, ADC0EB431FC36E88004079BB /* node_dialog_picker.cpp in Sources */, ADD7D2A01EBF9E1C00D5A897 /* image.cpp in Sources */, ADD7D2A11EBF9E1C00D5A897 /* texture.cpp in Sources */, @@ -1333,7 +1333,6 @@ DEVELOPMENT_TEAM = ERD9AYQ49S; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/libs/ZipArchive/Mac", ); INFOPLIST_FILE = "PanoPainter-OSX/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; @@ -1357,7 +1356,6 @@ DEVELOPMENT_TEAM = ERD9AYQ49S; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/libs/ZipArchive/Mac", ); INFOPLIST_FILE = "PanoPainter-OSX/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; @@ -1672,7 +1670,6 @@ DEVELOPMENT_TEAM = ERD9AYQ49S; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/libs/ZipArchive/iOS", ); HEADER_SEARCH_PATHS = ( "/Users/omimac/Downloads/curl-android-ios-master/prebuilt-with-ssl/iOS/include", @@ -1710,7 +1707,6 @@ DEVELOPMENT_TEAM = ERD9AYQ49S; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/libs/ZipArchive/iOS", ); HEADER_SEARCH_PATHS = ( "/Users/omimac/Downloads/curl-android-ios-master/prebuilt-with-ssl/iOS/include", diff --git a/PanoPainter/AppDelegate.m b/PanoPainter/AppDelegate.m index 08f3927..efdf467 100644 --- a/PanoPainter/AppDelegate.m +++ b/PanoPainter/AppDelegate.m @@ -11,22 +11,6 @@ #include "app.h" #include -void global_exception_handler(NSException* e) -{ - if (App::I.canvas && App::I.canvas->m_canvas) - App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); - - std::terminate(); -} - -void global_signal_handler(int e) -{ - if (App::I.canvas && App::I.canvas->m_canvas) - App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); - - std::terminate(); -} - @interface AppDelegate () { GameViewController* view; WTSonarPenDriver* sonarpen_driver; @@ -68,8 +52,6 @@ void global_signal_handler(int e) } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Override point for customization after application launch. - NSSetUncaughtExceptionHandler(&global_exception_handler); // sonarpen_driver = [[WTSonarPenDriver alloc] initWithApplication:application]; // [sonarpen_driver start]; // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(penStatusChanged) name:WTSonarPenDriverStateChangedNotification object:nil]; diff --git a/PanoPainter/main.m b/PanoPainter/main.cpp similarity index 86% rename from PanoPainter/main.m rename to PanoPainter/main.cpp index c9d05c6..c42e809 100644 --- a/PanoPainter/main.m +++ b/PanoPainter/main.cpp @@ -8,8 +8,10 @@ #import #import "AppDelegate.h" +#include "objc_utils.h" int main(int argc, char * argv[]) { + install_global_handlers(); @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } diff --git a/src/objc_utils.cpp b/src/objc_utils.cpp index b946c3d..2d963dd 100644 --- a/src/objc_utils.cpp +++ b/src/objc_utils.cpp @@ -1,12 +1,12 @@ #include "pch.h" #include "objc_utils.h" +#include "log.h" +#include "app.h" +#include #ifdef __OBJC__ - - @implementation PathWithModDate @end - @implementation ObjcUtils + (NSArray*)getFilesAtPathSortedByModificationDate:(NSString*)folderPath { @@ -34,3 +34,42 @@ } @end #endif + + +std::string base_address; +std::atomic_flag handler_executed; +void exception_handler(NSException *exception) +{ + if (handler_executed.test_and_set()) + exit(0); + LOG("exception %s\n", [[exception name] cStringUsingEncoding:NSUTF8StringEncoding]); + NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; + LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]); + if (App::I.canvas && App::I.canvas->m_canvas) + App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); + exit(0); +} + +static void signal_handler (int signo) { + if (handler_executed.test_and_set()) + exit(0); + LOG("signal %d\n", signo); + NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; + LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]); + if (App::I.canvas && App::I.canvas->m_canvas) + App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi"); + exit(0); +} + +void install_global_handlers() +{ + NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; + base_address = [callstack cStringUsingEncoding:NSUTF8StringEncoding]; + NSSetUncaughtExceptionHandler(exception_handler); + signal(SIGABRT, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGBUS, signal_handler); + signal(SIGPIPE, signal_handler); +} diff --git a/src/objc_utils.h b/src/objc_utils.h index 6046dbe..e0551b5 100644 --- a/src/objc_utils.h +++ b/src/objc_utils.h @@ -1,8 +1,6 @@ #pragma once #ifdef __OBJC__ - - @interface PathWithModDate : NSObject @property (strong) NSString *path; @property (strong) NSDate *modDate; @@ -10,6 +8,6 @@ @interface ObjcUtils : NSObject @end - - #endif + +void install_global_handlers(); diff --git a/src/pch.h b/src/pch.h index 321fcec..c3c2885 100644 --- a/src/pch.h +++ b/src/pch.h @@ -17,7 +17,6 @@ #import #import #import - #import #endif #include #include @@ -31,7 +30,6 @@ #import #import #import - #import #endif #include #include @@ -42,7 +40,6 @@ #ifdef __OBJC__ #import #import - #import #endif #include #include