Summary
The Backend.init function in imgui_backend.zig creates an ImGui context via ZigCraft_ImGui_CreateContext() at line 21, but if any subsequent initialization step fails (SDL3 backend at line 24 or Vulkan backend at line 44), the context is never destroyed. This causes a memory leak each time ImGui initialization fails.
Location
- File:
modules/engine-ui/src/imgui/imgui_backend.zig:21-47
- Function/Scope:
Backend.init
Severity: High
Memory leak on ImGui initialization failure
Impact
Every time the ImGui backend fails to initialize (e.g., due to Vulkan device loss, SDL3 window handle issues, or driver problems), the ImGui context allocated by ZigCraft_ImGui_CreateContext() is never freed. This leak accumulates over repeated initialization attempts and can cause memory exhaustion in long-running applications or when the graphics context is reset.
Evidence
In the init function, the ImGui context is created at line 21:
c.ZigCraft_ImGui_CreateContext(); // Line 21 - Context CREATED here
But if ZigCraft_ImGui_ImplSDL3_InitForVulkan fails at line 24, the function returns without destroying the context:
if (!c.ZigCraft_ImGui_ImplSDL3_InitForVulkan(@ptrCast(window))) {
log.log.err("Failed to initialize ImGui SDL3 backend", .{});
return error.ImguiBackendInitFailed; // Line 26 - BUG: context NOT destroyed!
}
Similarly, if ZigCraft_ImGui_ImplVulkan_Init fails at line 44, only SDL3 is shut down but the context is not destroyed:
if (!c.ZigCraft_ImGui_ImplVulkan_Init(&init_info)) {
c.ZigCraft_ImGui_ImplSDL3_Shutdown(); // Line 45 - SDL3 shut down
log.log.err("Failed to initialize ImGui Vulkan backend", .{});
return error.ImguiBackendInitFailed; // Line 47 - BUG: context NOT destroyed!
}
Compare with deinit() which properly destroys the context:
pub fn deinit(self: *Backend) void {
if (!build_options.imgui or !self.initialized) return;
c.ZigCraft_ImGui_ImplVulkan_Shutdown();
c.ZigCraft_ImGui_ImplSDL3_Shutdown();
c.ZigCraft_ImGui_DestroyContext(); // Context properly destroyed here
self.initialized = false;
}
The issue is that deinit() is never called when init() returns early with an error. The context created at line 21 becomes orphaned.
Proposed Fix
Add error recovery using errdefer to destroy the context on any failure path:
pub fn init(window: *sdl.SDL_Window, rhi_ptr: *rhi.RHI) !Backend {
if (!build_options.imgui) return error.ImguiDisabled;
errdefer c.ZigCraft_ImGui_DestroyContext();
c.ZigCraft_ImGui_CreateContext();
errdefer {
c.ZigCraft_ImGui_ImplSDL3_Shutdown();
c.ZigCraft_ImGui_DestroyContext();
}
c.ZigCraft_ImGui_StyleColorsDark();
if (!c.ZigCraft_ImGui_ImplSDL3_InitForVulkan(@ptrCast(window))) {
log.log.err("Failed to initialize ImGui SDL3 backend", .{});
return error.ImguiBackendInitFailed;
}
const native = rhi_ptr.nativeHandles();
// ... setup init_info ...
if (!c.ZigCraft_ImGui_ImplVulkan_Init(&init_info)) {
c.ZigCraft_ImGui_ImplVulkan_Shutdown();
c.ZigCraft_ImGui_ImplSDL3_Shutdown();
log.log.err("Failed to initialize ImGui Vulkan backend", .{});
return error.ImguiBackendInitFailed;
}
return .{ .initialized = true };
}
Acceptance Criteria
References
Summary
The
Backend.initfunction inimgui_backend.zigcreates an ImGui context viaZigCraft_ImGui_CreateContext()at line 21, but if any subsequent initialization step fails (SDL3 backend at line 24 or Vulkan backend at line 44), the context is never destroyed. This causes a memory leak each time ImGui initialization fails.Location
modules/engine-ui/src/imgui/imgui_backend.zig:21-47Backend.initSeverity: High
Memory leak on ImGui initialization failure
Impact
Every time the ImGui backend fails to initialize (e.g., due to Vulkan device loss, SDL3 window handle issues, or driver problems), the ImGui context allocated by
ZigCraft_ImGui_CreateContext()is never freed. This leak accumulates over repeated initialization attempts and can cause memory exhaustion in long-running applications or when the graphics context is reset.Evidence
In the
initfunction, the ImGui context is created at line 21:But if
ZigCraft_ImGui_ImplSDL3_InitForVulkanfails at line 24, the function returns without destroying the context:Similarly, if
ZigCraft_ImGui_ImplVulkan_Initfails at line 44, only SDL3 is shut down but the context is not destroyed:Compare with
deinit()which properly destroys the context:The issue is that
deinit()is never called wheninit()returns early with an error. The context created at line 21 becomes orphaned.Proposed Fix
Add error recovery using
errdeferto destroy the context on any failure path:Acceptance Criteria
nix develop --command zig build testpasses with no regressionsZigCraft_ImGui_CreateContexthas a correspondingZigCraft_ImGui_DestroyContexton all code paths)nix develop --command zig build testReferences
CreateContext()/DestroyContext()documentationerrdeferpattern for guaranteed cleanup: https://ziglang.org/documentation/master/#errdefer