From cdd3e38195bbe5e73b444323c1f765ae080a498f Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sun, 16 Aug 2026 20:24:26 +0900 Subject: [PATCH] fix(ibus): drop a context on the Service.Destroy libibus really sends libibus destroys an input context with Destroy on org.freedesktop.IBus.Service, not on the InputContext interface, so the call went unanswered and the context slot stayed taken until the whole connection closed. A long-lived GTK process that opens and closes text widgets exhausted the 1024 slots and then got LimitsExceeded for every new field. The live contract test now destroys a context that way and checks the path is gone. --- ibus.c | 4 ++++ tests/ibus_live_test.c | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/ibus.c b/ibus.c index e39cb73..a8c7693 100644 --- a/ibus.c +++ b/ibus.c @@ -854,6 +854,10 @@ onmsg(DBusConnection *c, DBusMessage *m, void*) if(strcmp(member, "GetAll") == 0) return handlepropertygetall(c, m); } + /* libibus destroys a context through its Service base interface. */ + if(strcmp(iface, "org.freedesktop.IBus.Service") == 0 && + strcmp(member, "Destroy") == 0) + iface = "org.freedesktop.IBus.InputContext"; if(strcmp(iface, "org.freedesktop.IBus.InputContext") == 0){ ctx = findcontext(c, path); if(ctx == nil) diff --git a/tests/ibus_live_test.c b/tests/ibus_live_test.c index fd1572e..5ba2fad 100644 --- a/tests/ibus_live_test.c +++ b/tests/ibus_live_test.c @@ -39,6 +39,31 @@ invalidcall(DBusConnection *conn, char *path, char *member) return ok; } +/* libibus destroys through the Service interface; the path must go away. */ +static int +destroyed(DBusConnection *conn, char *path) +{ + DBusMessage *m, *reply; + const char *name; + int ok; + + m = dbus_message_new_method_call("org.freedesktop.IBus", path, + "org.freedesktop.IBus.Service", "Destroy"); + reply = callret(conn, m, "Service.Destroy"); + if(reply == NULL) + return 0; + dbus_message_unref(reply); + reply = sendcall(conn, contextcall(path, "FocusIn"), "FocusIn"); + if(reply == NULL) + return 0; + name = dbus_message_get_error_name(reply); + ok = name != NULL && strcmp(name, DBUS_ERROR_UNKNOWN_OBJECT) == 0; + if(!ok) + fail("context survived Service.Destroy"); + dbus_message_unref(reply); + return ok; +} + static int overflowrejected(char *address) { @@ -115,6 +140,7 @@ runcontract(char *address) createcontext(conn, path, sizeof path, "contract context"); for(i = 0; ok && i < (int)(sizeof bad / sizeof bad[0]); i++) ok = invalidcall(conn, path, bad[i]); + ok = ok && destroyed(conn, path); closebus(&conn); return ok; }