SDL  2.0
SDL_assert.c File Reference
#include "./SDL_internal.h"
#include "SDL.h"
#include "SDL_atomic.h"
#include "SDL_messagebox.h"
#include "SDL_video.h"
#include "SDL_assert.h"
#include "SDL_assert_c.h"
#include "video/SDL_sysvideo.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+ Include dependency graph for SDL_assert.c:

Go to the source code of this file.

Macros

#define ENDLINE   "\n"

Functions

static SDL_assert_state SDL_PromptAssertion (const SDL_assert_data *data, void *userdata)
static void debug_print (const char *fmt,...)
static void SDL_AddAssertionToReport (SDL_assert_data *data)
static void SDL_GenerateAssertionReport (void)
static void SDL_ExitProcess (int exitcode)
static void SDL_AbortAssertion (void)
SDL_assert_state SDL_ReportAssertion (SDL_assert_data *data, const char *func, const char *file, int line)
void SDL_AssertionsQuit (void)
void SDL_SetAssertionHandler (SDL_AssertionHandler handler, void *userdata)
 Set an application-defined assertion handler.
const SDL_assert_dataSDL_GetAssertionReport (void)
 Get a list of all assertion failures.
void SDL_ResetAssertionReport (void)
 Reset the list of all assertion failures.
SDL_AssertionHandler SDL_GetDefaultAssertionHandler (void)
 Get the default assertion handler.
SDL_AssertionHandler SDL_GetAssertionHandler (void **userdata)
 Get the current assertion handler.

Variables

static SDL_assert_datatriggered_assertions = NULL
static SDL_mutexassertion_mutex = NULL
static SDL_AssertionHandler assertion_handler = SDL_PromptAssertion
static voidassertion_userdata = NULL

Macro Definition Documentation

#define ENDLINE   "\n"

Referenced by SDL_PromptAssertion().

Function Documentation

static void debug_print ( const char *  fmt,
  ... 
)
static

Definition at line 74 of file SDL_assert.c.

References SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, and SDL_LogMessageV.

Referenced by SDL_GenerateAssertionReport(), and SDL_PromptAssertion().

{
va_list ap;
va_start(ap, fmt);
va_end(ap);
}
static void SDL_AbortAssertion ( void  )
static

Definition at line 147 of file SDL_assert.c.

References SDL_ExitProcess(), and SDL_Quit.

Referenced by SDL_ReportAssertion().

static void SDL_AddAssertionToReport ( SDL_assert_data data)
static

Definition at line 83 of file SDL_assert.c.

References triggered_assertions.

Referenced by SDL_ReportAssertion().

{
/* (data) is always a static struct defined with the assert macros, so
we don't have to worry about copying or allocating them. */
data->trigger_count++;
if (data->trigger_count == 1) { /* not yet added? */
}
}
void SDL_AssertionsQuit ( void  )

Definition at line 397 of file SDL_assert.c.

References NULL, SDL_DestroyMutex, and SDL_GenerateAssertionReport().

Referenced by SDL_Quit().

{
#ifndef SDL_THREADS_DISABLED
}
#endif
}
static void SDL_ExitProcess ( int  exitcode)
static

Definition at line 126 of file SDL_assert.c.

Referenced by SDL_AbortAssertion(), and SDL_ReportAssertion().

{
#ifdef __WIN32__
/* "if you do not know the state of all threads in your process, it is
better to call TerminateProcess than ExitProcess"
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
TerminateProcess(GetCurrentProcess(), exitcode);
#elif defined(__EMSCRIPTEN__)
emscripten_cancel_main_loop(); /* this should "kill" the app. */
emscripten_force_exit(exitcode); /* this should "kill" the app. */
exit(exitcode);
#else
_exit(exitcode);
#endif
}
static void SDL_GenerateAssertionReport ( void  )
static

Definition at line 95 of file SDL_assert.c.

References assertion_handler, debug_print(), NULL, SDL_assert_data, SDL_PromptAssertion(), SDL_ResetAssertionReport, and triggered_assertions.

Referenced by SDL_AssertionsQuit().

{
/* only do this if the app hasn't assigned an assertion handler. */
if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
debug_print("\n\nSDL assertion report.\n");
debug_print("All SDL assertions between last init/quit:\n\n");
while (item != NULL) {
"'%s'\n"
" * %s (%s:%d)\n"
" * triggered %u time%s.\n"
" * always ignore: %s.\n",
item->condition, item->function, item->filename,
item->linenum, item->trigger_count,
(item->trigger_count == 1) ? "" : "s",
item->always_ignore ? "yes" : "no");
item = item->next;
}
debug_print("\n");
}
}
SDL_AssertionHandler SDL_GetAssertionHandler ( void **  puserdata)

Get the current assertion handler.

This returns the function pointer that is called when an assertion is triggered. This is either the value last passed to SDL_SetAssertionHandler(), or if no application-specified function is set, is equivalent to calling SDL_GetDefaultAssertionHandler().

Parameters
puserdataPointer to a void*, which will store the "userdata" pointer that was passed to SDL_SetAssertionHandler(). This value will always be NULL for the default handler. If you don't care about this data, it is safe to pass a NULL pointer to this function to ignore it.
Returns
The SDL_AssertionHandler that is called when an assert triggers.

Definition at line 443 of file SDL_assert.c.

References assertion_handler, assertion_userdata, and NULL.

{
if (userdata != NULL) {
*userdata = assertion_userdata;
}
}
const SDL_assert_data* SDL_GetAssertionReport ( void  )

Get a list of all assertion failures.

Get all assertions triggered since last call to SDL_ResetAssertionReport(), or the start of the program.

The proper way to examine this data looks something like this:

const SDL_AssertData *item = SDL_GetAssertionReport(); while (item) { printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\\n", item->condition, item->function, item->filename, item->linenum, item->trigger_count, item->always_ignore ? "yes" : "no"); item = item->next; }

Returns
List of all assertions.
See Also
SDL_ResetAssertionReport

Definition at line 419 of file SDL_assert.c.

References triggered_assertions.

SDL_AssertionHandler SDL_GetDefaultAssertionHandler ( void  )

Get the default assertion handler.

This returns the function pointer that is called by default when an assertion is triggered. This is an internal function provided by SDL, that is used for assertions when SDL_SetAssertionHandler() hasn't been used to provide a different function.

Returns
The default SDL_AssertionHandler that is called when an assert triggers.

Definition at line 438 of file SDL_assert.c.

References SDL_PromptAssertion().

{
}
static SDL_assert_state SDL_PromptAssertion ( const SDL_assert_data data,
void userdata 
)
static

Definition at line 155 of file SDL_assert.c.

References SDL_MessageBoxData::buttons, debug_print(), ENDLINE, SDL_MessageBoxData::flags, free, SDL_MessageBoxData::message, NULL, SDL_MessageBoxData::numbuttons, SDL_arraysize, SDL_assert_state, SDL_ASSERTION_ABORT, SDL_ASSERTION_ALWAYS_IGNORE, SDL_ASSERTION_BREAK, SDL_ASSERTION_IGNORE, SDL_ASSERTION_RETRY, SDL_FALSE, SDL_getenv, SDL_GetFocusWindow(), SDL_GetWindowFlags, SDL_MAX_LOG_MESSAGE, SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, SDL_MESSAGEBOX_WARNING, SDL_MinimizeWindow, SDL_RestoreWindow, SDL_ShowMessageBox, SDL_snprintf, SDL_stack_alloc, SDL_stack_free, SDL_strcmp, SDL_strncmp, SDL_TRUE, SDL_WINDOW_FULLSCREEN, SDL_zero, state, SDL_MessageBoxData::title, void, and SDL_MessageBoxData::window.

Referenced by SDL_GenerateAssertionReport(), SDL_GetDefaultAssertionHandler(), and SDL_SetAssertionHandler().

{
#ifdef __WIN32__
#define ENDLINE "\r\n"
#else
#define ENDLINE "\n"
#endif
const char *envr;
SDL_MessageBoxData messagebox;
{ 0, SDL_ASSERTION_RETRY, "Retry" },
{ 0, SDL_ASSERTION_BREAK, "Break" },
{ 0, SDL_ASSERTION_ABORT, "Abort" },
SDL_ASSERTION_IGNORE, "Ignore" },
SDL_ASSERTION_ALWAYS_IGNORE, "Always Ignore" }
};
char *message;
int selected;
(void) userdata; /* unused in default handler. */
if (!message) {
/* Uh oh, we're in real trouble now... */
}
"Assertion failure at %s (%s:%d), triggered %u %s:" ENDLINE
" '%s'",
data->function, data->filename, data->linenum,
data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
data->condition);
debug_print("\n\n%s\n\n", message);
/* let env. variable override, so unit tests won't block in a GUI. */
envr = SDL_getenv("SDL_ASSERT");
if (envr != NULL) {
SDL_stack_free(message);
if (SDL_strcmp(envr, "abort") == 0) {
} else if (SDL_strcmp(envr, "break") == 0) {
} else if (SDL_strcmp(envr, "retry") == 0) {
} else if (SDL_strcmp(envr, "ignore") == 0) {
} else if (SDL_strcmp(envr, "always_ignore") == 0) {
} else {
return SDL_ASSERTION_ABORT; /* oh well. */
}
}
/* Leave fullscreen mode, if possible (scary!) */
window = SDL_GetFocusWindow();
if (window) {
} else {
/* !!! FIXME: ungrab the input if we're not fullscreen? */
/* No need to mess with the window */
window = NULL;
}
}
/* Show a messagebox if we can, otherwise fall back to stdio */
SDL_zero(messagebox);
messagebox.window = window;
messagebox.title = "Assertion Failed";
messagebox.message = message;
messagebox.numbuttons = SDL_arraysize(buttons);
messagebox.buttons = buttons;
if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
if (selected == -1) {
} else {
state = (SDL_assert_state)selected;
}
}
else
{
#if defined(__EMSCRIPTEN__)
/* This is nasty, but we can't block on a custom UI. */
for ( ; ; ) {
char *buf = (char *) EM_ASM_INT({
var str =
Pointer_stringify($0) + '\n\n' +
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
var reply = window.prompt(str, "i");
if (reply === null) {
reply = "i";
}
return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL);
}, message);
if (SDL_strcmp(buf, "a") == 0) {
/* (currently) no break functionality on Emscripten
} else if (SDL_strcmp(buf, "b") == 0) {
state = SDL_ASSERTION_BREAK; */
} else if (SDL_strcmp(buf, "r") == 0) {
} else if (SDL_strcmp(buf, "i") == 0) {
} else if (SDL_strcmp(buf, "A") == 0) {
} else {
okay = SDL_FALSE;
}
free(buf);
if (okay) {
break;
}
}
#elif defined(HAVE_STDIO_H)
/* this is a little hacky. */
for ( ; ; ) {
char buf[32];
fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
fflush(stderr);
if (fgets(buf, sizeof (buf), stdin) == NULL) {
break;
}
if (SDL_strncmp(buf, "a", 1) == 0) {
break;
} else if (SDL_strncmp(buf, "b", 1) == 0) {
break;
} else if (SDL_strncmp(buf, "r", 1) == 0) {
break;
} else if (SDL_strncmp(buf, "i", 1) == 0) {
break;
} else if (SDL_strncmp(buf, "A", 1) == 0) {
break;
}
}
#endif /* HAVE_STDIO_H */
}
/* Re-enter fullscreen mode */
if (window) {
}
SDL_stack_free(message);
return state;
}
SDL_assert_state SDL_ReportAssertion ( SDL_assert_data data,
const char *  func,
const char *  file,
int  line 
)

Definition at line 323 of file SDL_assert.c.

References assertion_handler, assertion_userdata, NULL, SDL_AbortAssertion(), SDL_AddAssertionToReport(), SDL_assert_state, SDL_ASSERTION_ABORT, SDL_ASSERTION_ALWAYS_IGNORE, SDL_ASSERTION_BREAK, SDL_ASSERTION_IGNORE, SDL_ASSERTION_RETRY, SDL_AtomicLock, SDL_AtomicUnlock, SDL_CreateMutex, SDL_ExitProcess(), SDL_LockMutex, SDL_UnlockMutex, and state.

{
static int assertion_running = 0;
#ifndef SDL_THREADS_DISABLED
static SDL_SpinLock spinlock = 0;
SDL_AtomicLock(&spinlock);
if (assertion_mutex == NULL) { /* never called SDL_Init()? */
SDL_AtomicUnlock(&spinlock);
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
}
}
SDL_AtomicUnlock(&spinlock);
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
}
#endif
/* doing this because Visual C is upset over assigning in the macro. */
if (data->trigger_count == 0) {
data->function = func;
data->filename = file;
data->linenum = line;
}
assertion_running++;
if (assertion_running > 1) { /* assert during assert! Abort. */
if (assertion_running == 2) {
} else if (assertion_running == 3) { /* Abort asserted! */
} else {
while (1) { /* do nothing but spin; what else can you do?! */ }
}
}
if (!data->always_ignore) {
}
switch (state)
{
return SDL_ASSERTION_IGNORE; /* shouldn't return, but oh well. */
data->always_ignore = 1;
break;
break; /* macro handles these. */
}
assertion_running--;
#ifndef SDL_THREADS_DISABLED
#endif
return state;
}
void SDL_ResetAssertionReport ( void  )

Reset the list of all assertion failures.

Reset list of all assertions triggered.

See Also
SDL_GetAssertionReport

Definition at line 424 of file SDL_assert.c.

References NULL, SDL_assert_data, SDL_FALSE, and triggered_assertions.

{
for (item = triggered_assertions; item != NULL; item = next) {
next = (SDL_assert_data *) item->next;
item->always_ignore = SDL_FALSE;
item->trigger_count = 0;
item->next = NULL;
}
}
void SDL_SetAssertionHandler ( SDL_AssertionHandler  handler,
void userdata 
)

Set an application-defined assertion handler.

This allows an app to show its own assertion UI and/or force the response to an assertion failure. If the app doesn't provide this, SDL will try to do the right thing, popping up a system-specific GUI dialog, and probably minimizing any fullscreen windows.

This callback may fire from any thread, but it runs wrapped in a mutex, so it will only fire from one thread at a time.

Setting the callback to NULL restores SDL's original internal handler.

This callback is NOT reset to SDL's internal handler upon SDL_Quit()!

Return SDL_AssertState value of how to handle the assertion failure.

Parameters
handlerCallback function, called when an assertion fails.
userdataA pointer passed to the callback as-is.

Definition at line 408 of file SDL_assert.c.

References assertion_handler, assertion_userdata, NULL, and SDL_PromptAssertion().

{
if (handler != NULL) {
assertion_handler = handler;
assertion_userdata = userdata;
} else {
}
}

Variable Documentation

SDL_mutex* assertion_mutex = NULL
static

Definition at line 62 of file SDL_assert.c.

void* assertion_userdata = NULL
static