From 122d3d09ca415822e6b81a44a6dd91589c33654e Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Sun, 19 Oct 2025 18:16:34 +0800 Subject: [PATCH] Improve API safety This improves API Layer: - Add runtime NULL checks for all API functions - Add backend function pointer validation before use - Graceful error handling in release builds via log_error() - Fix twin_destroy() to validate context before backend exit --- src/api.c | 37 +++++++++++++++++++++++++++++++------ src/dispatch.c | 8 -------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/api.c b/src/api.c index 2f019720..8d7f4240 100644 --- a/src/api.c +++ b/src/api.c @@ -22,13 +22,17 @@ extern twin_backend_t g_twin_backend; */ twin_context_t *twin_create(int width, int height) { + /* Runtime check for missing backend */ + if (!g_twin_backend.init) { + log_error("Backend not registered - no init function"); + return NULL; + } + assert(g_twin_backend.init && "Backend not registered"); twin_context_t *ctx = g_twin_backend.init(width, height); if (!ctx) { -#ifdef CONFIG_LOGGING - log_error("Failed to initialize Twin context (%dx%d)", width, height); -#endif + log_error("Backend initialization failed (%dx%d)", width, height); } return ctx; } @@ -42,10 +46,18 @@ twin_context_t *twin_create(int width, int height) */ void twin_destroy(twin_context_t *ctx) { + if (!ctx) + return; + + /* Runtime check for missing backend */ + if (!g_twin_backend.exit) { + log_error("Backend not registered - no exit function"); + return; + } + assert(g_twin_backend.exit && "Backend not registered"); - if (ctx) - g_twin_backend.exit(ctx); + g_twin_backend.exit(ctx); } /** @@ -57,11 +69,24 @@ void twin_destroy(twin_context_t *ctx) * * @ctx : Twin context to run * @init_callback : Application initialization function (called once before - * event loop) + * event loop) */ void twin_run(twin_context_t *ctx, void (*init_callback)(twin_context_t *)) { + /* Validate context parameter */ + if (!ctx) { + log_error("NULL context passed to twin_run"); + return; + } + assert(ctx && "NULL context passed to twin_run"); + + /* Runtime check for missing start function */ + if (!g_twin_backend.start) { + log_error("Backend has no start function - main loop not running"); + return; + } + assert(g_twin_backend.start && "Backend start function not registered"); g_twin_backend.start(ctx, init_callback); diff --git a/src/dispatch.c b/src/dispatch.c index eae6cd0b..ae56ffea 100644 --- a/src/dispatch.c +++ b/src/dispatch.c @@ -41,9 +41,7 @@ bool twin_dispatch_once(twin_context_t *ctx) { /* Validate context to prevent null pointer dereference in callbacks */ if (!ctx) { -#ifdef CONFIG_LOGGING log_error("twin_dispatch_once: NULL context"); -#endif return false; } @@ -57,9 +55,7 @@ bool twin_dispatch_once(twin_context_t *ctx) if (!g_twin_backend.poll(ctx)) return false; } else { -#ifdef CONFIG_LOGGING log_warn("twin_dispatch_once: No backend poll function registered"); -#endif /* Yield CPU to avoid busy-waiting when no event source available */ #ifdef __EMSCRIPTEN__ emscripten_sleep(0); @@ -94,18 +90,14 @@ void twin_dispatch(twin_context_t *ctx) * Calling twin_dispatch() directly will not work in WebAssembly. */ (void) ctx; /* Unused in Emscripten builds */ -#ifdef CONFIG_LOGGING log_error( "twin_dispatch() called in Emscripten build - use " "twin_dispatch_once() with emscripten_set_main_loop_arg()"); -#endif return; #else /* Validate context before entering event loop */ if (!ctx) { -#ifdef CONFIG_LOGGING log_error("twin_dispatch: NULL context"); -#endif return; }