Common: Use NSAlert for assertion failures/panics

This commit is contained in:
Stenzek
2025-10-29 22:15:35 +10:00
parent 94cfc9ba2e
commit efa6e4aeca
2 changed files with 82 additions and 23 deletions

View File

@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#if !defined(__APPLE__) && !defined(__ANDROID__)
#include "assert.h"
#include "crash_handler.h"
@@ -71,27 +73,6 @@ static void ResumeThreads(HANDLE hSnapshot)
}
}
#else
#ifdef __ANDROID__
// Define as a weak symbol for ancient devices that don't have it.
extern "C" __attribute__((weak)) void android_set_abort_message(const char*);
#endif
[[noreturn]] ALWAYS_INLINE static void AbortWithMessage(const char* szMsg)
{
#ifndef __ANDROID__
std::fputs(szMsg, stderr);
std::fflush(stderr);
std::abort();
#else
if (&android_set_abort_message)
android_set_abort_message(szMsg);
std::abort();
#endif
}
#endif // _WIN32
void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
@@ -125,7 +106,9 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
ResumeThreads(pHandle);
#else
AbortWithMessage(szMsg);
std::fputs(szMsg, stderr);
std::fflush(stderr);
std::abort();
#endif
}
@@ -157,6 +140,10 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
ResumeThreads(pHandle);
#else
AbortWithMessage(szMsg);
std::fputs(szMsg, stderr);
std::fflush(stderr);
std::abort();
#endif
}
#endif // !defined(__APPLE__) && !defined(__ANDROID__)

View File

@@ -8,6 +8,8 @@
#include "fmt/format.h"
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include <cinttypes>
#include <dlfcn.h>
#include <mach/mach_time.h>
@@ -142,3 +144,73 @@ bool CocoaTools::DelayedLaunch(std::string_view file, std::span<const std::strin
return [task launchAndReturnError:nil];
}
}
void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(),
[szMessage, szFunction, szFile, uLine]() { Y_OnAssertFailed(szMessage, szFunction, szFile, uLine); });
return;
}
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
std::fputs(szMsg, stderr);
std::fflush(stderr);
@autoreleasepool
{
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:@"Assertion Failed"];
NSString* text = [NSString stringWithFormat:@"%s in function %s (%s:%u)\nPress Abort to exit, Break to break to "
@"debugger, or Ignore to attempt to continue.",
szMessage, szFunction, szFile, uLine];
[alert setInformativeText:text];
[alert setAlertStyle:NSAlertStyleCritical];
[alert addButtonWithTitle:@"Abort"];
[alert addButtonWithTitle:@"Break"];
[alert addButtonWithTitle:@"Ignore"];
const NSModalResponse response = [alert runModal];
if (response == NSAlertFirstButtonReturn)
std::abort();
else if (response == NSAlertSecondButtonReturn)
__builtin_debugtrap();
}
}
[[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(),
[szMessage, szFunction, szFile, uLine]() { Y_OnAssertFailed(szMessage, szFunction, szFile, uLine); });
}
else
{
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
@autoreleasepool
{
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:@"Critical Error"];
NSString* text =
[NSString stringWithFormat:@"%s in function %s (%s:%u)\nDo you want to attempt to break into a debugger?",
szMessage, szFunction, szFile, uLine];
[alert setInformativeText:text];
[alert setAlertStyle:NSAlertStyleCritical];
[alert addButtonWithTitle:@"Abort"];
[alert addButtonWithTitle:@"Break"];
const NSModalResponse response = [alert runModal];
if (response == NSAlertSecondButtonReturn)
__builtin_debugtrap();
}
}
std::abort();
}