n_gui_process_event re-entrancy regression test (headless).
n_gui_process_event re-entrancy regression test (headless). A button on_click that opens/raises another window reorders ctx->windows (n_gui_raise_window removes + re-pushes + re-sorts the window list). The mouse-release handler in n_gui_process_event iterates ctx->windows while firing that callback; firing it inline freed the LIST_NODE the iterator had already cached as "next", a use-after-free that crashed on the following step. This test reproduces the exact click (press then release over the button) headlessly and asserts the callback fired and the process survives, which under ASan fails loudly if the deferred-dispatch fix regresses.
#define ALLEGRO_UNSTABLE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
(void)widget_id;
(void)user_data;
}
}
if (!cond) {
} else {
}
}
int opt;
while ((opt = getopt(argc, argv, "V:")) != -1) {
switch (opt) {
case 'V':
if (!strcmp("LOG_NULL", optarg))
else if (!strcmp("LOG_NOTICE", optarg))
else if (!strcmp("LOG_INFO", optarg))
else if (!strcmp("LOG_ERR", optarg))
else if (!strcmp("LOG_DEBUG", optarg))
else
return -1;
break;
default:
return -1;
}
}
return 0;
}
static ALLEGRO_EVENT
mouse_event(
int type,
int x,
int y) {
ALLEGRO_EVENT ev;
memset(&ev, 0, sizeof(ev));
ev.type = (unsigned int)type;
ev.mouse.x = x;
ev.mouse.y = y;
ev.mouse.button = 1;
return ev;
}
int main(
int argc,
char** argv) {
fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
return 2;
}
if (!al_init()) {
return 1;
}
if (!al_init_font_addon()) {
return 1;
}
ALLEGRO_FONT* font = al_create_builtin_font();
if (!font) {
return 1;
}
al_destroy_font(font);
return 1;
}
{
ALLEGRO_EVENT down =
mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 50, 25);
ALLEGRO_EVENT up =
mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_UP, 50, 25);
}
{
ALLEGRO_EVENT down =
mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 50, 25);
ALLEGRO_EVENT up =
mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_UP, 50, 25);
}
al_destroy_font(font);
return 1;
}
return 0;
}
void process_args(int argc, char **argv)
static void expect_true(const char *label, int cond)
static ALLEGRO_EVENT mouse_event(int type, int x, int y)
static void on_open_popup(int widget_id, void *user_data)
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
Set the display (viewport) size for global scrollbar computation.
void n_gui_raise_window(N_GUI_CTX *ctx, int window_id)
Bring a window to the front (top of draw order).
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
void n_gui_window_set_zorder(N_GUI_CTX *ctx, int window_id, int z_mode, int z_value)
Set window z-order mode and value.
#define N_GUI_WIN_FRAMELESS
frameless window: no title bar drawn, drag via window body unless N_GUI_WIN_FIXED_POSITION is also se...
int n_gui_window_is_open(N_GUI_CTX *ctx, int window_id)
Check if a window is currently visible.
int n_gui_add_window(N_GUI_CTX *ctx, const char *title, float x, float y, float w, float h)
Add a new pseudo-window to the context.
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
void n_gui_open_window(N_GUI_CTX *ctx, int window_id)
Open (show) a window.
#define N_GUI_ZORDER_POPUP
popup/modal dialogs: drawn above EVERYTHING including ALWAYS_ON_TOP windows.
#define N_GUI_SHAPE_ROUNDED
rounded rectangle shape
void n_gui_window_set_flags(N_GUI_CTX *ctx, int window_id, int flags)
Set feature flags on a window.
int n_gui_add_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, void(*on_click)(int, void *), void *user_data)
Add a button widget to a window.
The top-level GUI context that holds all windows.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
#define LOG_NULL
no log output
#define LOG_INFO
informational
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.