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 SDL_NORETURN void SDL_ExitProcess (int exitcode)
 
static SDL_NORETURN 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. More...
 
const SDL_assert_dataSDL_GetAssertionReport (void)
 Get a list of all assertion failures. More...
 
void SDL_ResetAssertionReport (void)
 Reset the list of all assertion failures. More...
 
SDL_AssertionHandler SDL_GetDefaultAssertionHandler (void)
 Get the default assertion handler. More...
 
SDL_AssertionHandler SDL_GetAssertionHandler (void **userdata)
 Get the current assertion handler. More...
 

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

◆ ENDLINE

#define ENDLINE   "\n"

Function Documentation

◆ debug_print()

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

Definition at line 74 of file SDL_assert.c.

75{
76 va_list ap;
77 va_start(ap, fmt);
79 va_end(ap);
80}
#define SDL_LogMessageV
@ SDL_LOG_PRIORITY_WARN
Definition: SDL_log.h:107
@ SDL_LOG_CATEGORY_ASSERT
Definition: SDL_log.h:68

References SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, and SDL_LogMessageV.

Referenced by SDL_GenerateAssertionReport(), and SDL_PromptAssertion().

◆ SDL_AbortAssertion()

static SDL_NORETURN void SDL_AbortAssertion ( void  )
static

Definition at line 153 of file SDL_assert.c.

154{
155 SDL_Quit();
156 SDL_ExitProcess(42);
157}
static SDL_NORETURN void SDL_ExitProcess(int exitcode)
Definition: SDL_assert.c:126
#define SDL_Quit

References SDL_ExitProcess(), and SDL_Quit.

Referenced by SDL_ReportAssertion().

◆ SDL_AddAssertionToReport()

static void SDL_AddAssertionToReport ( SDL_assert_data data)
static

Definition at line 83 of file SDL_assert.c.

84{
85 /* (data) is always a static struct defined with the assert macros, so
86 we don't have to worry about copying or allocating them. */
87 data->trigger_count++;
88 if (data->trigger_count == 1) { /* not yet added? */
91 }
92}
static SDL_assert_data * triggered_assertions
Definition: SDL_assert.c:59
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974

References triggered_assertions.

Referenced by SDL_ReportAssertion().

◆ SDL_AssertionsQuit()

void SDL_AssertionsQuit ( void  )

Definition at line 404 of file SDL_assert.c.

405{
407#ifndef SDL_THREADS_DISABLED
408 if (assertion_mutex != NULL) {
411 }
412#endif
413}
static void SDL_GenerateAssertionReport(void)
Definition: SDL_assert.c:95
static SDL_mutex * assertion_mutex
Definition: SDL_assert.c:62
#define SDL_DestroyMutex
#define NULL
Definition: begin_code.h:167

References assertion_mutex, NULL, SDL_DestroyMutex, and SDL_GenerateAssertionReport().

Referenced by SDL_Quit().

◆ SDL_ExitProcess()

static SDL_NORETURN void SDL_ExitProcess ( int  exitcode)
static

Definition at line 126 of file SDL_assert.c.

127{
128#ifdef __WIN32__
129 /* "if you do not know the state of all threads in your process, it is
130 better to call TerminateProcess than ExitProcess"
131 https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
132 TerminateProcess(GetCurrentProcess(), exitcode);
133 /* MingW doesn't have TerminateProcess marked as noreturn, so add an
134 ExitProcess here that will never be reached but make MingW happy. */
135 ExitProcess(exitcode);
136#elif defined(__EMSCRIPTEN__)
137 emscripten_cancel_main_loop(); /* this should "kill" the app. */
138 emscripten_force_exit(exitcode); /* this should "kill" the app. */
139 exit(exitcode);
140#elif defined(__HAIKU__) /* Haiku has _Exit, but it's not marked noreturn. */
141 _exit(exitcode);
142#elif defined(HAVE__EXIT) /* Upper case _Exit() */
143 _Exit(exitcode);
144#else
145 _exit(exitcode);
146#endif
147}

Referenced by SDL_AbortAssertion(), and SDL_ReportAssertion().

◆ SDL_GenerateAssertionReport()

static void SDL_GenerateAssertionReport ( void  )
static

Definition at line 95 of file SDL_assert.c.

96{
98
99 /* only do this if the app hasn't assigned an assertion handler. */
100 if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
101 debug_print("\n\nSDL assertion report.\n");
102 debug_print("All SDL assertions between last init/quit:\n\n");
103
104 while (item != NULL) {
106 "'%s'\n"
107 " * %s (%s:%d)\n"
108 " * triggered %u time%s.\n"
109 " * always ignore: %s.\n",
110 item->condition, item->function, item->filename,
111 item->linenum, item->trigger_count,
112 (item->trigger_count == 1) ? "" : "s",
113 item->always_ignore ? "yes" : "no");
114 item = item->next;
115 }
116 debug_print("\n");
117
119 }
120}
static SDL_assert_state SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
Definition: SDL_assert.c:161
void SDL_ResetAssertionReport(void)
Reset the list of all assertion failures.
Definition: SDL_assert.c:431
static SDL_AssertionHandler assertion_handler
Definition: SDL_assert.c:65
static void debug_print(const char *fmt,...)
Definition: SDL_assert.c:74
#define SDL_assert_data
Definition: SDL_assert.h:280

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

Referenced by SDL_AssertionsQuit().

◆ SDL_GetAssertionHandler()

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 450 of file SDL_assert.c.

451{
452 if (userdata != NULL) {
453 *userdata = assertion_userdata;
454 }
455 return assertion_handler;
456}
static void * assertion_userdata
Definition: SDL_assert.c:66

References assertion_handler, assertion_userdata, and NULL.

◆ SDL_GetAssertionReport()

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 426 of file SDL_assert.c.

427{
429}

References triggered_assertions.

◆ SDL_GetDefaultAssertionHandler()

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 445 of file SDL_assert.c.

446{
447 return SDL_PromptAssertion;
448}

References SDL_PromptAssertion().

◆ SDL_PromptAssertion()

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

Definition at line 161 of file SDL_assert.c.

162{
163#ifdef __WIN32__
164 #define ENDLINE "\r\n"
165#else
166 #define ENDLINE "\n"
167#endif
168
169 const char *envr;
172 SDL_MessageBoxData messagebox;
173 SDL_MessageBoxButtonData buttons[] = {
174 { 0, SDL_ASSERTION_RETRY, "Retry" },
175 { 0, SDL_ASSERTION_BREAK, "Break" },
176 { 0, SDL_ASSERTION_ABORT, "Abort" },
178 SDL_ASSERTION_IGNORE, "Ignore" },
180 SDL_ASSERTION_ALWAYS_IGNORE, "Always Ignore" }
181 };
182 char *message;
183 int selected;
184
185 (void) userdata; /* unused in default handler. */
186
187 /* !!! FIXME: why is this using SDL_stack_alloc and not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
189 if (!message) {
190 /* Uh oh, we're in real trouble now... */
191 return SDL_ASSERTION_ABORT;
192 }
194 "Assertion failure at %s (%s:%d), triggered %u %s:" ENDLINE
195 " '%s'",
196 data->function, data->filename, data->linenum,
197 data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
198 data->condition);
199
200 debug_print("\n\n%s\n\n", message);
201
202 /* let env. variable override, so unit tests won't block in a GUI. */
203 envr = SDL_getenv("SDL_ASSERT");
204 if (envr != NULL) {
206
207 if (SDL_strcmp(envr, "abort") == 0) {
208 return SDL_ASSERTION_ABORT;
209 } else if (SDL_strcmp(envr, "break") == 0) {
210 return SDL_ASSERTION_BREAK;
211 } else if (SDL_strcmp(envr, "retry") == 0) {
212 return SDL_ASSERTION_RETRY;
213 } else if (SDL_strcmp(envr, "ignore") == 0) {
215 } else if (SDL_strcmp(envr, "always_ignore") == 0) {
217 } else {
218 return SDL_ASSERTION_ABORT; /* oh well. */
219 }
220 }
221
222 /* Leave fullscreen mode, if possible (scary!) */
224 if (window) {
227 } else {
228 /* !!! FIXME: ungrab the input if we're not fullscreen? */
229 /* No need to mess with the window */
230 window = NULL;
231 }
232 }
233
234 /* Show a messagebox if we can, otherwise fall back to stdio */
235 SDL_zero(messagebox);
236 messagebox.flags = SDL_MESSAGEBOX_WARNING;
237 messagebox.window = window;
238 messagebox.title = "Assertion Failed";
239 messagebox.message = message;
240 messagebox.numbuttons = SDL_arraysize(buttons);
241 messagebox.buttons = buttons;
242
243 if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
244 if (selected == -1) {
246 } else {
247 state = (SDL_assert_state)selected;
248 }
249 }
250
251 else
252 {
253#if defined(__EMSCRIPTEN__)
254 /* This is nasty, but we can't block on a custom UI. */
255 for ( ; ; ) {
256 SDL_bool okay = SDL_TRUE;
257 char *buf = (char *) EM_ASM_INT({
258 var str =
259 UTF8ToString($0) + '\n\n' +
260 'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
261 var reply = window.prompt(str, "i");
262 if (reply === null) {
263 reply = "i";
264 }
265 return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL);
266 }, message);
267
268 if (SDL_strcmp(buf, "a") == 0) {
270 /* (currently) no break functionality on Emscripten
271 } else if (SDL_strcmp(buf, "b") == 0) {
272 state = SDL_ASSERTION_BREAK; */
273 } else if (SDL_strcmp(buf, "r") == 0) {
275 } else if (SDL_strcmp(buf, "i") == 0) {
277 } else if (SDL_strcmp(buf, "A") == 0) {
279 } else {
280 okay = SDL_FALSE;
281 }
282 free(buf);
283
284 if (okay) {
285 break;
286 }
287 }
288#elif defined(HAVE_STDIO_H)
289 /* this is a little hacky. */
290 for ( ; ; ) {
291 char buf[32];
292 fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
293 fflush(stderr);
294 if (fgets(buf, sizeof (buf), stdin) == NULL) {
295 break;
296 }
297
298 if (SDL_strncmp(buf, "a", 1) == 0) {
300 break;
301 } else if (SDL_strncmp(buf, "b", 1) == 0) {
303 break;
304 } else if (SDL_strncmp(buf, "r", 1) == 0) {
306 break;
307 } else if (SDL_strncmp(buf, "i", 1) == 0) {
309 break;
310 } else if (SDL_strncmp(buf, "A", 1) == 0) {
312 break;
313 }
314 }
315#endif /* HAVE_STDIO_H */
316 }
317
318 /* Re-enter fullscreen mode */
319 if (window) {
321 }
322
324
325 return state;
326}
#define ENDLINE
@ SDL_ASSERTION_RETRY
Definition: SDL_assert.h:104
@ SDL_ASSERTION_ABORT
Definition: SDL_assert.h:106
@ SDL_ASSERTION_IGNORE
Definition: SDL_assert.h:107
@ SDL_ASSERTION_BREAK
Definition: SDL_assert.h:105
@ SDL_ASSERTION_ALWAYS_IGNORE
Definition: SDL_assert.h:108
#define SDL_assert_state
Definition: SDL_assert.h:279
#define SDL_strncmp
#define SDL_RestoreWindow
#define SDL_GetWindowFlags
#define SDL_getenv
#define SDL_strcmp
#define SDL_ShowMessageBox
#define SDL_MinimizeWindow
#define SDL_snprintf
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
SDL_EventEntry * free
Definition: SDL_events.c:82
#define SDL_MAX_LOG_MESSAGE
The maximum size of a log message.
Definition: SDL_log.h:54
@ SDL_MESSAGEBOX_WARNING
@ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT
@ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT
GLuint GLsizei const GLchar * message
GLenum GLuint GLenum GLsizei const GLchar * buf
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
SDL_Window * SDL_GetFocusWindow(void)
Definition: SDL_video.c:2696
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:100
struct xkb_state * state
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
Individual button data.
MessageBox structure containing title, text, window, etc.
const SDL_MessageBoxButtonData * buttons
SDL_Window * window
const char * title
const char * message
The type used to identify a window.
Definition: SDL_sysvideo.h:74

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().

◆ SDL_ReportAssertion()

SDL_assert_state SDL_ReportAssertion ( SDL_assert_data data,
const char *  func,
const char *  file,
int  line 
)

Definition at line 330 of file SDL_assert.c.

332{
334 static int assertion_running = 0;
335
336#ifndef SDL_THREADS_DISABLED
337 static SDL_SpinLock spinlock = 0;
338 SDL_AtomicLock(&spinlock);
339 if (assertion_mutex == NULL) { /* never called SDL_Init()? */
341 if (assertion_mutex == NULL) {
342 SDL_AtomicUnlock(&spinlock);
343 return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
344 }
345 }
346 SDL_AtomicUnlock(&spinlock);
347
349 return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
350 }
351#endif
352
353 /* doing this because Visual C is upset over assigning in the macro. */
354 if (data->trigger_count == 0) {
355 data->function = func;
356 data->filename = file;
357 data->linenum = line;
358 }
359
361
362 assertion_running++;
363 if (assertion_running > 1) { /* assert during assert! Abort. */
364 if (assertion_running == 2) {
366 } else if (assertion_running == 3) { /* Abort asserted! */
367 SDL_ExitProcess(42);
368 } else {
369 while (1) { /* do nothing but spin; what else can you do?! */ }
370 }
371 }
372
373 if (!data->always_ignore) {
375 }
376
377 switch (state)
378 {
381 data->always_ignore = 1;
382 break;
383
387 break; /* macro handles these. */
388
391 /*break; ...shouldn't return, but oh well. */
392 }
393
394 assertion_running--;
395
396#ifndef SDL_THREADS_DISABLED
398#endif
399
400 return state;
401}
static void SDL_AddAssertionToReport(SDL_assert_data *data)
Definition: SDL_assert.c:83
static SDL_NORETURN void SDL_AbortAssertion(void)
Definition: SDL_assert.c:153
int SDL_SpinLock
Definition: SDL_atomic.h:89
#define SDL_AtomicLock
#define SDL_LockMutex
#define SDL_CreateMutex
#define SDL_AtomicUnlock
#define SDL_UnlockMutex
GLenum func

References assertion_handler, assertion_mutex, 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.

◆ SDL_ResetAssertionReport()

void SDL_ResetAssertionReport ( void  )

Reset the list of all assertion failures.

Reset list of all assertions triggered.

See also
SDL_GetAssertionReport

Definition at line 431 of file SDL_assert.c.

432{
433 SDL_assert_data *next = NULL;
434 SDL_assert_data *item;
435 for (item = triggered_assertions; item != NULL; item = next) {
436 next = (SDL_assert_data *) item->next;
437 item->always_ignore = SDL_FALSE;
438 item->trigger_count = 0;
439 item->next = NULL;
440 }
441
443}

References NULL, SDL_assert_data, SDL_FALSE, and triggered_assertions.

Referenced by SDL_GenerateAssertionReport().

◆ SDL_SetAssertionHandler()

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 415 of file SDL_assert.c.

416{
417 if (handler != NULL) {
418 assertion_handler = handler;
419 assertion_userdata = userdata;
420 } else {
423 }
424}

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

Variable Documentation

◆ assertion_handler

◆ assertion_mutex

SDL_mutex* assertion_mutex = NULL
static

Definition at line 62 of file SDL_assert.c.

Referenced by SDL_AssertionsQuit(), and SDL_ReportAssertion().

◆ assertion_userdata

void* assertion_userdata = NULL
static

◆ triggered_assertions