git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitca36f5be3fa3795f1fe09c215ce7eed2309334ba
parent566184c35c
authorIsaac Freund <[email protected]>
date2021-08-12 22:38
river-status: fix output status destruction

There was a use-after-free if the Output was destroyed first, and the
memory of the output status was leaked.

 river/OutputStatus.zig | 10 ++++++++--
 river/Root.zig         |  2 ++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/river/OutputStatus.zig b/river/OutputStatus.zig
index e6e6045..2000126 100644
--- a/river/OutputStatus.zig
+++ b/river/OutputStatus.zig
@@ -43,6 +43,13 @@ pub fn init(self: *Self, output: *Output, output_status: *zriver.OutputStatusV1)
     self.sendFocusedTags(output.current.tags);
 }
 
+pub fn destroy(self: *Self) void {
+    const node = @fieldParentPtr(std.SinglyLinkedList(Self).Node, "data", self);
+    self.output.status_trackers.remove(node);
+    self.output_status.setHandler(*Self, handleRequest, null, self);
+    util.gpa.destroy(node);
+}
+
 fn handleRequest(output_status: *zriver.OutputStatusV1, request: zriver.OutputStatusV1.Request, self: *Self) void {
     switch (request) {
         .destroy => output_status.destroy(),
@@ -50,8 +57,7 @@ fn handleRequest(output_status: *zriver.OutputStatusV1, request: zriver.OutputSt
 }
 
 fn handleDestroy(output_status: *zriver.OutputStatusV1, self: *Self) void {
-    const node = @fieldParentPtr(std.SinglyLinkedList(Self).Node, "data", self);
-    self.output.status_trackers.remove(node);
+    self.destroy();
 }
 
 /// Send the current tags of each view on the output to the client.
diff --git a/river/Root.zig b/river/Root.zig
index 33792d8..3af4ec1 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -203,6 +203,8 @@ pub fn removeOutput(self: *Self, output: *Output) void {
     // Destroy all layouts of the output
     while (output.layouts.first) |layout_node| layout_node.data.destroy();
 
+    while (output.status_trackers.first) |status_node| status_node.data.destroy();
+
     // Arrange the root in case evacuated views affect the layout
     fallback_output.arrangeViews();
     self.startTransaction();