src/SDL_assert.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 28 Feb 2018 01:23:49 -0500
changeset 11908 97092601ea78
parent 11811 5d94cb6b24d3
child 11911 235c5929651c
permissions -rw-r--r--
assert: Use TerminateProcess() on Windows, vs ExitProcess (thanks, Jack!).

"What I have done is use TerminateProcess rather than ExitProcess.
ExitProcess will cause Microsoft's leak detection to continue, TerminateProcess
won't. It is also technically wrong to use ExitProcess in the case of aborting
the application.

Jack Powell
Twitter @jack9267"
slouken@3647
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@3647
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@3647
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@3647
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@3647
    20
*/
icculus@8093
    21
#include "./SDL_internal.h"
slouken@3647
    22
slouken@7828
    23
#if defined(__WIN32__)
slouken@7828
    24
#include "core/windows/SDL_windows.h"
slouken@7828
    25
#endif
slouken@7828
    26
slouken@3651
    27
#include "SDL.h"
slouken@5006
    28
#include "SDL_atomic.h"
slouken@6621
    29
#include "SDL_messagebox.h"
slouken@6621
    30
#include "SDL_video.h"
slouken@3647
    31
#include "SDL_assert.h"
slouken@4472
    32
#include "SDL_assert_c.h"
slouken@3671
    33
#include "video/SDL_sysvideo.h"
slouken@3647
    34
slouken@5086
    35
#ifdef __WIN32__
slouken@5086
    36
#ifndef WS_OVERLAPPEDWINDOW
slouken@5086
    37
#define WS_OVERLAPPEDWINDOW 0
slouken@5086
    38
#endif
slouken@3647
    39
#else  /* fprintf, _exit(), etc. */
slouken@3647
    40
#include <stdio.h>
slouken@3647
    41
#include <stdlib.h>
dludwig@8341
    42
#if ! defined(__WINRT__)
icculus@3648
    43
#include <unistd.h>
slouken@3647
    44
#endif
dludwig@8341
    45
#endif
slouken@3647
    46
icculus@11017
    47
#if defined(__EMSCRIPTEN__)
icculus@11017
    48
#include <emscripten.h>
icculus@11017
    49
#endif
icculus@11017
    50
icculus@11017
    51
slouken@11272
    52
static SDL_assert_state SDLCALL
icculus@3670
    53
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
icculus@3670
    54
icculus@3670
    55
/*
icculus@3670
    56
 * We keep all triggered assertions in a singly-linked list so we can
slouken@3647
    57
 *  generate a report later.
slouken@3647
    58
 */
icculus@5541
    59
static SDL_assert_data *triggered_assertions = NULL;
icculus@3670
    60
icculus@11015
    61
#ifndef SDL_THREADS_DISABLED
icculus@3670
    62
static SDL_mutex *assertion_mutex = NULL;
icculus@11015
    63
#endif
icculus@11015
    64
icculus@3670
    65
static SDL_AssertionHandler assertion_handler = SDL_PromptAssertion;
icculus@3670
    66
static void *assertion_userdata = NULL;
slouken@3647
    67
icculus@3648
    68
#ifdef __GNUC__
icculus@3661
    69
static void
icculus@3661
    70
debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
icculus@3648
    71
#endif
icculus@3648
    72
icculus@3648
    73
static void
icculus@3648
    74
debug_print(const char *fmt, ...)
slouken@3647
    75
{
slouken@3647
    76
    va_list ap;
slouken@3647
    77
    va_start(ap, fmt);
slouken@6621
    78
    SDL_LogMessageV(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, fmt, ap);
slouken@3647
    79
    va_end(ap);
slouken@3647
    80
}
slouken@3647
    81
slouken@3647
    82
slouken@3647
    83
static void SDL_AddAssertionToReport(SDL_assert_data *data)
slouken@3647
    84
{
slouken@3647
    85
    /* (data) is always a static struct defined with the assert macros, so
slouken@3647
    86
       we don't have to worry about copying or allocating them. */
icculus@5541
    87
    data->trigger_count++;
icculus@5541
    88
    if (data->trigger_count == 1) {  /* not yet added? */
slouken@3647
    89
        data->next = triggered_assertions;
slouken@3647
    90
        triggered_assertions = data;
slouken@3647
    91
    }
slouken@3647
    92
}
slouken@3647
    93
icculus@3670
    94
slouken@3647
    95
static void SDL_GenerateAssertionReport(void)
slouken@3647
    96
{
icculus@5541
    97
    const SDL_assert_data *item = triggered_assertions;
icculus@3670
    98
icculus@3670
    99
    /* only do this if the app hasn't assigned an assertion handler. */
icculus@5541
   100
    if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
slouken@3647
   101
        debug_print("\n\nSDL assertion report.\n");
slouken@3647
   102
        debug_print("All SDL assertions between last init/quit:\n\n");
slouken@3647
   103
icculus@5541
   104
        while (item != NULL) {
slouken@3647
   105
            debug_print(
slouken@3647
   106
                "'%s'\n"
slouken@3647
   107
                "    * %s (%s:%d)\n"
slouken@3647
   108
                "    * triggered %u time%s.\n"
slouken@3647
   109
                "    * always ignore: %s.\n",
slouken@3647
   110
                item->condition, item->function, item->filename,
slouken@3647
   111
                item->linenum, item->trigger_count,
slouken@3647
   112
                (item->trigger_count == 1) ? "" : "s",
slouken@3647
   113
                item->always_ignore ? "yes" : "no");
slouken@3647
   114
            item = item->next;
slouken@3647
   115
        }
slouken@3647
   116
        debug_print("\n");
slouken@3647
   117
icculus@3670
   118
        SDL_ResetAssertionReport();
slouken@3647
   119
    }
slouken@3647
   120
}
slouken@3647
   121
slouken@10616
   122
slouken@10616
   123
static SDL_NORETURN void SDL_ExitProcess(int exitcode)
slouken@3647
   124
{
slouken@5086
   125
#ifdef __WIN32__
icculus@11908
   126
    /* "if you do not know the state of all threads in your process, it is
icculus@11908
   127
       better to call TerminateProcess than ExitProcess"
icculus@11908
   128
       https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
icculus@11908
   129
    TerminateProcess(GetCurrentProcess(), exitcode);
icculus@11908
   130
icculus@11017
   131
#elif defined(__EMSCRIPTEN__)
icculus@11017
   132
    emscripten_cancel_main_loop();  /* this should "kill" the app. */
icculus@11017
   133
    emscripten_force_exit(exitcode);  /* this should "kill" the app. */
icculus@11017
   134
    exit(exitcode);
slouken@3656
   135
#else
icculus@6305
   136
    _exit(exitcode);
slouken@3647
   137
#endif
slouken@3647
   138
}
icculus@3661
   139
slouken@10616
   140
slouken@10616
   141
static SDL_NORETURN void SDL_AbortAssertion(void)
icculus@3661
   142
{
icculus@3661
   143
    SDL_Quit();
icculus@3661
   144
    SDL_ExitProcess(42);
icculus@3661
   145
}
icculus@3661
   146
slouken@3647
   147
slouken@11272
   148
static SDL_assert_state SDLCALL
icculus@3670
   149
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
slouken@3647
   150
{
icculus@6759
   151
#ifdef __WIN32__
icculus@6759
   152
    #define ENDLINE "\r\n"
icculus@6759
   153
#else
icculus@6759
   154
    #define ENDLINE "\n"
icculus@6759
   155
#endif
icculus@6759
   156
slouken@3647
   157
    const char *envr;
slouken@3657
   158
    SDL_assert_state state = SDL_ASSERTION_ABORT;
slouken@3685
   159
    SDL_Window *window;
slouken@6621
   160
    SDL_MessageBoxData messagebox;
slouken@6621
   161
    SDL_MessageBoxButtonData buttons[] = {
slouken@6621
   162
        {   0,  SDL_ASSERTION_RETRY,            "Retry" },
slouken@6621
   163
        {   0,  SDL_ASSERTION_BREAK,            "Break" },
slouken@6621
   164
        {   0,  SDL_ASSERTION_ABORT,            "Abort" },
slouken@6621
   165
        {   SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
slouken@6621
   166
                SDL_ASSERTION_IGNORE,           "Ignore" },
slouken@6621
   167
        {   SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
slouken@6621
   168
                SDL_ASSERTION_ALWAYS_IGNORE,    "Always Ignore" }
slouken@6621
   169
    };
slouken@6621
   170
    char *message;
slouken@6621
   171
    int selected;
slouken@3647
   172
icculus@3670
   173
    (void) userdata;  /* unused in default handler. */
icculus@3670
   174
slouken@6621
   175
    message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
slouken@6621
   176
    if (!message) {
slouken@6621
   177
        /* Uh oh, we're in real trouble now... */
slouken@6621
   178
        return SDL_ASSERTION_ABORT;
slouken@6621
   179
    }
slouken@6621
   180
    SDL_snprintf(message, SDL_MAX_LOG_MESSAGE,
icculus@6759
   181
                 "Assertion failure at %s (%s:%d), triggered %u %s:" ENDLINE
icculus@6759
   182
                    "  '%s'",
slouken@6621
   183
                 data->function, data->filename, data->linenum,
slouken@6621
   184
                 data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
slouken@6621
   185
                 data->condition);
slouken@6621
   186
slouken@6621
   187
    debug_print("\n\n%s\n\n", message);
slouken@3647
   188
slouken@3655
   189
    /* let env. variable override, so unit tests won't block in a GUI. */
slouken@3647
   190
    envr = SDL_getenv("SDL_ASSERT");
slouken@3647
   191
    if (envr != NULL) {
slouken@6621
   192
        SDL_stack_free(message);
slouken@6621
   193
slouken@3647
   194
        if (SDL_strcmp(envr, "abort") == 0) {
slouken@3647
   195
            return SDL_ASSERTION_ABORT;
slouken@3647
   196
        } else if (SDL_strcmp(envr, "break") == 0) {
slouken@3647
   197
            return SDL_ASSERTION_BREAK;
slouken@3647
   198
        } else if (SDL_strcmp(envr, "retry") == 0) {
slouken@3647
   199
            return SDL_ASSERTION_RETRY;
slouken@3647
   200
        } else if (SDL_strcmp(envr, "ignore") == 0) {
slouken@3647
   201
            return SDL_ASSERTION_IGNORE;
slouken@3647
   202
        } else if (SDL_strcmp(envr, "always_ignore") == 0) {
slouken@3647
   203
            return SDL_ASSERTION_ALWAYS_IGNORE;
slouken@3647
   204
        } else {
slouken@3647
   205
            return SDL_ASSERTION_ABORT;  /* oh well. */
slouken@3647
   206
        }
slouken@3647
   207
    }
slouken@3647
   208
slouken@3657
   209
    /* Leave fullscreen mode, if possible (scary!) */
slouken@3657
   210
    window = SDL_GetFocusWindow();
slouken@3657
   211
    if (window) {
slouken@3657
   212
        if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
slouken@3657
   213
            SDL_MinimizeWindow(window);
slouken@3657
   214
        } else {
icculus@3670
   215
            /* !!! FIXME: ungrab the input if we're not fullscreen? */
slouken@3657
   216
            /* No need to mess with the window */
slouken@6621
   217
            window = NULL;
slouken@3657
   218
        }
slouken@3657
   219
    }
slouken@3657
   220
slouken@6621
   221
    /* Show a messagebox if we can, otherwise fall back to stdio */
slouken@6621
   222
    SDL_zero(messagebox);
slouken@6621
   223
    messagebox.flags = SDL_MESSAGEBOX_WARNING;
slouken@6621
   224
    messagebox.window = window;
slouken@6621
   225
    messagebox.title = "Assertion Failed";
slouken@6621
   226
    messagebox.message = message;
slouken@6621
   227
    messagebox.numbuttons = SDL_arraysize(buttons);
slouken@6621
   228
    messagebox.buttons = buttons;
slouken@3647
   229
slouken@6621
   230
    if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
slouken@6621
   231
        if (selected == -1) {
slouken@3657
   232
            state = SDL_ASSERTION_IGNORE;
slouken@6621
   233
        } else {
slouken@6621
   234
            state = (SDL_assert_state)selected;
slouken@3647
   235
        }
slouken@3647
   236
    }
icculus@11017
   237
slouken@6621
   238
    else
slouken@6621
   239
    {
icculus@11017
   240
#if defined(__EMSCRIPTEN__)
icculus@11017
   241
        /* This is nasty, but we can't block on a custom UI. */
icculus@11017
   242
        for ( ; ; ) {
icculus@11017
   243
            SDL_bool okay = SDL_TRUE;
icculus@11017
   244
            char *buf = (char *) EM_ASM_INT({
icculus@11017
   245
                var str =
icculus@11017
   246
                    Pointer_stringify($0) + '\n\n' +
icculus@11017
   247
                    'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
icculus@11017
   248
                var reply = window.prompt(str, "i");
icculus@11017
   249
                if (reply === null) {
icculus@11017
   250
                    reply = "i";
icculus@11017
   251
                }
icculus@11017
   252
                return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL);
icculus@11017
   253
            }, message);
icculus@11017
   254
icculus@11017
   255
            if (SDL_strcmp(buf, "a") == 0) {
icculus@11017
   256
                state = SDL_ASSERTION_ABORT;
icculus@11017
   257
            /* (currently) no break functionality on Emscripten
icculus@11017
   258
            } else if (SDL_strcmp(buf, "b") == 0) {
icculus@11017
   259
                state = SDL_ASSERTION_BREAK; */
icculus@11017
   260
            } else if (SDL_strcmp(buf, "r") == 0) {
icculus@11017
   261
                state = SDL_ASSERTION_RETRY;
icculus@11017
   262
            } else if (SDL_strcmp(buf, "i") == 0) {
icculus@11017
   263
                state = SDL_ASSERTION_IGNORE;
icculus@11017
   264
            } else if (SDL_strcmp(buf, "A") == 0) {
icculus@11017
   265
                state = SDL_ASSERTION_ALWAYS_IGNORE;
icculus@11017
   266
            } else {
icculus@11017
   267
                okay = SDL_FALSE;
icculus@11017
   268
            }
icculus@11017
   269
            free(buf);
icculus@11017
   270
icculus@11017
   271
            if (okay) {
icculus@11017
   272
                break;
icculus@11017
   273
            }
icculus@11017
   274
        }
icculus@11017
   275
#elif defined(HAVE_STDIO_H)
slouken@6621
   276
        /* this is a little hacky. */
slouken@6621
   277
        for ( ; ; ) {
slouken@6621
   278
            char buf[32];
slouken@6621
   279
            fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
slouken@6621
   280
            fflush(stderr);
slouken@6621
   281
            if (fgets(buf, sizeof (buf), stdin) == NULL) {
slouken@6621
   282
                break;
slouken@6621
   283
            }
slouken@6621
   284
slouken@11626
   285
            if (SDL_strncmp(buf, "a", 1) == 0) {
slouken@6621
   286
                state = SDL_ASSERTION_ABORT;
slouken@6621
   287
                break;
slouken@11626
   288
            } else if (SDL_strncmp(buf, "b", 1) == 0) {
slouken@6621
   289
                state = SDL_ASSERTION_BREAK;
slouken@6621
   290
                break;
slouken@11626
   291
            } else if (SDL_strncmp(buf, "r", 1) == 0) {
slouken@6621
   292
                state = SDL_ASSERTION_RETRY;
slouken@6621
   293
                break;
slouken@11626
   294
            } else if (SDL_strncmp(buf, "i", 1) == 0) {
slouken@6621
   295
                state = SDL_ASSERTION_IGNORE;
slouken@6621
   296
                break;
slouken@11626
   297
            } else if (SDL_strncmp(buf, "A", 1) == 0) {
slouken@6621
   298
                state = SDL_ASSERTION_ALWAYS_IGNORE;
slouken@6621
   299
                break;
slouken@6621
   300
            }
slouken@6621
   301
        }
icculus@11017
   302
#endif /* HAVE_STDIO_H */
slouken@6621
   303
    }
slouken@3647
   304
slouken@3657
   305
    /* Re-enter fullscreen mode */
slouken@3657
   306
    if (window) {
slouken@3657
   307
        SDL_RestoreWindow(window);
slouken@3657
   308
    }
slouken@3657
   309
slouken@6621
   310
    SDL_stack_free(message);
slouken@6621
   311
slouken@3657
   312
    return state;
slouken@3647
   313
}
slouken@3647
   314
slouken@3647
   315
slouken@3647
   316
SDL_assert_state
slouken@3655
   317
SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
slouken@3655
   318
                    int line)
slouken@3647
   319
{
icculus@11015
   320
    SDL_assert_state state = SDL_ASSERTION_IGNORE;
icculus@3661
   321
    static int assertion_running = 0;
icculus@11015
   322
icculus@11015
   323
#ifndef SDL_THREADS_DISABLED
icculus@3662
   324
    static SDL_SpinLock spinlock = 0;
icculus@3662
   325
    SDL_AtomicLock(&spinlock);
icculus@3662
   326
    if (assertion_mutex == NULL) { /* never called SDL_Init()? */
icculus@3662
   327
        assertion_mutex = SDL_CreateMutex();
icculus@3662
   328
        if (assertion_mutex == NULL) {
icculus@3662
   329
            SDL_AtomicUnlock(&spinlock);
icculus@3662
   330
            return SDL_ASSERTION_IGNORE;   /* oh well, I guess. */
icculus@3662
   331
        }
icculus@3662
   332
    }
icculus@3662
   333
    SDL_AtomicUnlock(&spinlock);
icculus@3662
   334
slouken@3647
   335
    if (SDL_LockMutex(assertion_mutex) < 0) {
slouken@3647
   336
        return SDL_ASSERTION_IGNORE;   /* oh well, I guess. */
slouken@3647
   337
    }
icculus@11015
   338
#endif
slouken@3647
   339
slouken@3647
   340
    /* doing this because Visual C is upset over assigning in the macro. */
slouken@3647
   341
    if (data->trigger_count == 0) {
slouken@3647
   342
        data->function = func;
slouken@3655
   343
        data->filename = file;
slouken@3655
   344
        data->linenum = line;
slouken@3647
   345
    }
slouken@3647
   346
slouken@3647
   347
    SDL_AddAssertionToReport(data);
slouken@3647
   348
icculus@3661
   349
    assertion_running++;
icculus@3661
   350
    if (assertion_running > 1) {   /* assert during assert! Abort. */
icculus@3661
   351
        if (assertion_running == 2) {
icculus@3661
   352
            SDL_AbortAssertion();
icculus@3661
   353
        } else if (assertion_running == 3) {  /* Abort asserted! */
icculus@3661
   354
            SDL_ExitProcess(42);
icculus@3661
   355
        } else {
icculus@3661
   356
            while (1) { /* do nothing but spin; what else can you do?! */ }
icculus@3661
   357
        }
slouken@3647
   358
    }
slouken@3647
   359
icculus@3661
   360
    if (!data->always_ignore) {
icculus@3670
   361
        state = assertion_handler(data, assertion_userdata);
icculus@3661
   362
    }
slouken@3647
   363
slouken@3647
   364
    switch (state)
slouken@3647
   365
    {
slouken@3647
   366
        case SDL_ASSERTION_ABORT:
slouken@3647
   367
            SDL_AbortAssertion();
slouken@3647
   368
            return SDL_ASSERTION_IGNORE;  /* shouldn't return, but oh well. */
slouken@3647
   369
slouken@3647
   370
        case SDL_ASSERTION_ALWAYS_IGNORE:
slouken@3647
   371
            state = SDL_ASSERTION_IGNORE;
slouken@3647
   372
            data->always_ignore = 1;
slouken@3647
   373
            break;
slouken@3647
   374
slouken@3647
   375
        case SDL_ASSERTION_IGNORE:
slouken@3647
   376
        case SDL_ASSERTION_RETRY:
slouken@3647
   377
        case SDL_ASSERTION_BREAK:
slouken@3647
   378
            break;  /* macro handles these. */
slouken@3647
   379
    }
slouken@3647
   380
icculus@3661
   381
    assertion_running--;
icculus@11015
   382
icculus@11015
   383
#ifndef SDL_THREADS_DISABLED
slouken@3647
   384
    SDL_UnlockMutex(assertion_mutex);
icculus@11015
   385
#endif
slouken@3647
   386
slouken@3647
   387
    return state;
slouken@3647
   388
}
slouken@3647
   389
slouken@3647
   390
slouken@3647
   391
void SDL_AssertionsQuit(void)
slouken@3647
   392
{
slouken@3647
   393
    SDL_GenerateAssertionReport();
icculus@11015
   394
#ifndef SDL_THREADS_DISABLED
icculus@3664
   395
    if (assertion_mutex != NULL) {
icculus@3664
   396
        SDL_DestroyMutex(assertion_mutex);
icculus@3664
   397
        assertion_mutex = NULL;
icculus@3664
   398
    }
icculus@11015
   399
#endif
icculus@3670
   400
}
icculus@3670
   401
icculus@3670
   402
void SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
icculus@3670
   403
{
icculus@3670
   404
    if (handler != NULL) {
icculus@3670
   405
        assertion_handler = handler;
icculus@3670
   406
        assertion_userdata = userdata;
icculus@3670
   407
    } else {
icculus@3670
   408
        assertion_handler = SDL_PromptAssertion;
icculus@3670
   409
        assertion_userdata = NULL;
icculus@3670
   410
    }
icculus@3670
   411
}
icculus@3670
   412
icculus@3670
   413
const SDL_assert_data *SDL_GetAssertionReport(void)
icculus@3670
   414
{
icculus@3670
   415
    return triggered_assertions;
icculus@3670
   416
}
icculus@3670
   417
icculus@3670
   418
void SDL_ResetAssertionReport(void)
icculus@3670
   419
{
icculus@3670
   420
    SDL_assert_data *next = NULL;
icculus@5541
   421
    SDL_assert_data *item;
icculus@5541
   422
    for (item = triggered_assertions; item != NULL; item = next) {
icculus@3670
   423
        next = (SDL_assert_data *) item->next;
icculus@3670
   424
        item->always_ignore = SDL_FALSE;
icculus@3670
   425
        item->trigger_count = 0;
icculus@3670
   426
        item->next = NULL;
icculus@3670
   427
    }
icculus@3670
   428
icculus@5541
   429
    triggered_assertions = NULL;
slouken@3647
   430
}
slouken@3647
   431
icculus@8167
   432
SDL_AssertionHandler SDL_GetDefaultAssertionHandler(void)
icculus@8167
   433
{
icculus@8167
   434
    return SDL_PromptAssertion;
icculus@8167
   435
}
icculus@8167
   436
icculus@8167
   437
SDL_AssertionHandler SDL_GetAssertionHandler(void **userdata)
icculus@8167
   438
{
icculus@8167
   439
    if (userdata != NULL) {
icculus@8167
   440
        *userdata = assertion_userdata;
icculus@8167
   441
    }
icculus@8167
   442
    return assertion_handler;
icculus@8167
   443
}
icculus@8167
   444
slouken@3647
   445
/* vi: set ts=4 sw=4 expandtab: */