From 8e6c28da7bc6e8916b6ee7e4ced4e28c5e733a53 Mon Sep 17 00:00:00 2001 From: Ben Buhse Date: Sun, 22 Feb 2026 17:38:28 -0600 Subject: [PATCH] Fix some memory leaks --- src/Context.zig | 7 +++++++ src/InputManager.zig | 2 ++ src/LibinputDevice.zig | 3 ++- src/Output.zig | 17 +++++++++++++---- src/WindowManager.zig | 8 ++++++++ src/XkbBindings.zig | 1 + src/main.zig | 9 ++++----- 7 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/Context.zig b/src/Context.zig index 1d867ec..d894f2c 100644 --- a/src/Context.zig +++ b/src/Context.zig @@ -116,6 +116,13 @@ pub fn destroy(context: *Context) void { if (context.tag_overlay_timer_fd) |fd| posix.close(fd); context.buffer_pool.deinit(); + // Destroy Wayland globals + context.river_layer_shell_v1.destroy(); + context.zwlr_layer_shell_v1.destroy(); + context.wl_shm.destroy(); + context.wl_compositor.destroy(); + context.wl_registry.destroy(); + utils.gpa.destroy(context); } diff --git a/src/InputManager.zig b/src/InputManager.zig index b99a3c5..1e13bad 100644 --- a/src/InputManager.zig +++ b/src/InputManager.zig @@ -38,6 +38,8 @@ pub fn create(context: *Context, river_input_manager_v1: *river.InputManagerV1, } pub fn destroy(im: *InputManager) void { + im.river_input_manager_v1.destroy(); + im.river_libinput_config_v1.destroy(); utils.gpa.destroy(im); } diff --git a/src/LibinputDevice.zig b/src/LibinputDevice.zig index 59eeab6..f605747 100644 --- a/src/LibinputDevice.zig +++ b/src/LibinputDevice.zig @@ -285,12 +285,13 @@ fn isSupported(comptime E: type, comptime S: type, val: E, support: S) bool { /// log any unsupported or invalid config responses from the compositor. fn applyResult(result: anyerror!*river.LibinputResultV1) void { const Listener = struct { - fn resultListener(_: *river.LibinputResultV1, event: river.LibinputResultV1.Event, _: ?*anyopaque) void { + fn resultListener(libinput_result: *river.LibinputResultV1, event: river.LibinputResultV1.Event, _: ?*anyopaque) void { switch (event) { .success => {}, .unsupported => log.debug("Config option unsupported by device", .{}), .invalid => log.warn("Invalid config value for device", .{}), } + libinput_result.destroy(); } }; diff --git a/src/Output.zig b/src/Output.zig index 7930412..4c06cee 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -118,20 +118,28 @@ pub fn create(context: *Context, river_output_v1: *river.OutputV1) !*Output { } pub fn destroy(output: *Output) void { + // Destroy any windows left on the Output + // This *should* be empty var it = output.windows.safeIterator(.forward); while (it.next()) |window| { window.link.remove(); window.destroy(); } + // Deinit optional surfaces if (output.bar) |*bar| bar.deinit(); if (output.tag_overlay) |*tag_overlay| tag_overlay.deinit(); - - output.tag_layout_overrides.deinit(utils.gpa); output.deinitWallpaperLayerSurface(); - if (output.wl_output) |wl_output| wl_output.release(); - output.river_output_v1.destroy(); + + // Destroy/deinit other Output fields + output.tag_layout_overrides.deinit(utils.gpa); + if (output.name) |name| utils.gpa.free(name); + + // Destroy/release relevant Wayland interfaces output.river_layer_shell_output_v1.destroy(); + output.river_output_v1.destroy(); + if (output.wl_output) |wl_output| wl_output.release(); + utils.gpa.destroy(output); } @@ -302,6 +310,7 @@ fn wlOutputListener(_: *wl.Output, event: wl.Output.Event, output: *Output) void output.scale = @intCast(ev.factor); }, .name => |ev| { + if (output.name) |old_name| utils.gpa.free(old_name); output.name = utils.gpa.dupe(u8, mem.span(ev.name)) catch @panic("Out of memory"); }, else => {}, diff --git a/src/WindowManager.zig b/src/WindowManager.zig index e5f5f2d..40c18e3 100644 --- a/src/WindowManager.zig +++ b/src/WindowManager.zig @@ -52,7 +52,15 @@ pub fn destroy(wm: *WindowManager) void { seat.destroy(); } } + { + var it = wm.orphan_windows.safeIterator(.forward); + while (it.next()) |window| { + window.link.remove(); + window.destroy(); + } + } + wm.river_window_manager_v1.destroy(); utils.gpa.destroy(wm); } diff --git a/src/XkbBindings.zig b/src/XkbBindings.zig index 60f889a..3aa41fe 100644 --- a/src/XkbBindings.zig +++ b/src/XkbBindings.zig @@ -489,6 +489,7 @@ pub fn destroy(xkb_bindings: *XkbBindings) void { binding.xkb_binding_v1.destroy(); utils.gpa.destroy(binding); } + xkb_bindings.xkb_bindings_v1.destroy(); utils.gpa.destroy(xkb_bindings); } diff --git a/src/main.zig b/src/main.zig index 62f898b..d847a13 100644 --- a/src/main.zig +++ b/src/main.zig @@ -40,12 +40,11 @@ pub fn main() !void { _ = fcft.init(.auto, false, fcft_log_level); defer fcft.fini(); - const wayland_display_var = try utils.gpa.dupeZ(u8, process.getEnvVarOwned(utils.gpa, "WAYLAND_DISPLAY") catch { - fatal("Error getting WAYLAND_DISPLAY environment variable. Exiting", .{}); - }); - defer utils.gpa.free(wayland_display_var); + const wayland_display_var = posix.getenvZ("WAYLAND_DISPLAY") orelse { + fatal("WAYLAND_DISPLAY environment variable not set. Exiting", .{}); + }; - const wl_display = wl.Display.connect(null) catch { + const wl_display = wl.Display.connect(wayland_display_var) catch { fatal("Error connecting to Wayland server. Exiting", .{}); }; defer wl_display.disconnect();