[education/rkward] rkward/rbackend: Fix resource leak

Thomas Friedrichsmeier null at kde.org
Sun Sep 14 19:26:16 BST 2025


Git commit 959c2020955cf71eeffe15a46e08ebcbca2399d3 by Thomas Friedrichsmeier.
Committed on 12/09/2025 at 20:49.
Pushed by tfry into branch 'master'.

Fix resource leak

M  +16   -2    rkward/rbackend/rkrbackend.cpp

https://invent.kde.org/education/rkward/-/commit/959c2020955cf71eeffe15a46e08ebcbca2399d3

diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index 47124fcb1..8e541c79b 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -111,8 +111,10 @@ void RKRBackend::interruptCommand(int command_id) {
 	 *     current_command, feeding it into the REPL/eval) -> handled in beginAllowInterruptCommand()
 	 *  2) when it is properly running in the backend -> this is the typical case, we worry about, "immediate interrupt", below
 	 *  2b) when it is properly running in the backend, but there is also an active sub-command, which we should allow to complete
-	 *      -> see commands_to_cancel_deferred and handleDeferredInterrupts()
-	 *  3) after it has finished running in the backend, but the frontend wasn't aware of that, yet TODO: fix resource leak
+	 *     -> see commands_to_cancel_deferred and handleDeferredInterrupts()
+	 *  3) after it has finished running in the backend, but the frontend wasn't aware of that, yet
+	 *     -> to prevent resource leakage, we check for unknown ids to cancel when a new command has just been received in
+	 *        handleRequest(). At this point we are sure, it cannot be case 1), above.
 	 *
 	 * The procedure to interrupt the current command (case 2, above), is also quite complex. Some sources of complication:
 	 * 1) Requests to interrupt will originate outside the R thread.
@@ -1466,6 +1468,18 @@ RCommandProxy *RKRBackend::handleRequest2(RBackendRequest *request, bool mayHand
 		RK_ASSERT(command != current_command);
 		command->outer_command = current_command;
 		current_command = command;
+
+		// clean up after stale deferred interrupts (see comments in interruptCommand()
+		for (int i = commands_to_cancel_deferred.size() - 1; i >= 0; --i) {
+			const auto id = commands_to_cancel_deferred[i];
+			auto c = current_command;
+			bool found = false;
+			do {
+				if (c->id == id) found = true;
+				c = c->outer_command;
+			} while (c && !found);
+			if (!found) commands_to_cancel_deferred.removeAt(i);
+		}
 	}
 
 	if (!mayHandleSubstack) return command;



More information about the rkward-tracker mailing list