Skip to content

Commit

Permalink
src/message_iter: Maintain reference to underlying DBusMessage
Browse files Browse the repository at this point in the history
Weirdly, an DBusMessageIter doesn't increase the refcount of the
referred DBusMessage, thus we need to maintain the reference manually to
avoid underlying DBusMessage gets garbagecollected before the
DBusMessageIter, which results in a dangling reference.

Let's introduce a new type, lDBusMessageIter, which contains both the
iterator and the underlying DBusMessage, and refer/unref the message
during creation, initialization and garbage collection of the iterator.

Closes: daurnimator#20
Signed-off-by: Yao Zi <[email protected]>
  • Loading branch information
ziyao233 committed Feb 1, 2025
1 parent 6d4909c commit 3afdbee
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 14 deletions.
16 changes: 12 additions & 4 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,32 +134,40 @@ static int ldbus_message_get_type(lua_State *L) {

static int ldbus_message_iter_init(lua_State *L) {
DBusMessage *message = check_DBusMessage(L, 1);
DBusMessageIter *iter;
lDBusMessageIter *iter;
if (lua_gettop(L) == 1) {
push_DBusMessageIter(L);
} else {
lua_settop(L, 2);
unref_dbus_message_iter(L);
}
iter = luaL_checkudata(L, 2, DBUS_MESSAGE_ITER_METATABLE);

if (!dbus_message_iter_init(message, iter)) {
if (!dbus_message_iter_init(message, &iter->iter)) {
lua_pushnil(L);
}

iter->message = message;
dbus_message_ref(message);

return 1;
}

static int ldbus_message_iter_init_append(lua_State *L) {
DBusMessage *message = check_DBusMessage(L, 1);
DBusMessageIter *iter;
lDBusMessageIter *iter;
if (lua_gettop(L) == 1) {
push_DBusMessageIter(L);
} else {
lua_settop(L, 2);
unref_dbus_message_iter(L);
}
iter = luaL_checkudata(L, 2, DBUS_MESSAGE_ITER_METATABLE);

dbus_message_iter_init_append(message, iter);
dbus_message_iter_init_append(message, &iter->iter);

iter->message = message;
dbus_message_ref(iter->message);

return 1;
}
Expand Down
50 changes: 40 additions & 10 deletions src/message_iter.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,27 @@
#include "message_iter.h"


LDBUS_INTERNAL int unref_dbus_message_iter(lua_State *L) {
lDBusMessageIter *iter = luaL_checkudata(L, -1, DBUS_MESSAGE_ITER_METATABLE);

if (iter->message) {
dbus_message_unref(iter->message);
}

return 0;
}

static int ldbus_message_iter_clone(lua_State *L) {
DBusMessageIter *iter = luaL_checkudata(L, 1, DBUS_MESSAGE_ITER_METATABLE);
DBusMessageIter *clone;
lDBusMessageIter *iter = luaL_checkudata(L, 1, DBUS_MESSAGE_ITER_METATABLE);
lDBusMessageIter *clone;
push_DBusMessageIter(L);
clone = lua_touserdata(L, -1);
memcpy(clone, iter, sizeof(DBusMessageIter));
memcpy(clone, iter, sizeof(lDBusMessageIter));

if (clone->message) {
dbus_message_ref(clone->message);
}

return 1;
}

Expand Down Expand Up @@ -65,16 +80,21 @@ static int ldbus_message_iter_get_element_type(lua_State *L) {
}

static int ldbus_message_iter_recurse(lua_State *L) {
DBusMessageIter *iter = luaL_checkudata(L, 1, DBUS_MESSAGE_ITER_METATABLE);
DBusMessageIter *sub;
lDBusMessageIter *iter = luaL_checkudata(L, 1, DBUS_MESSAGE_ITER_METATABLE);
lDBusMessageIter *sub;
if (lua_gettop(L) == 1) {
push_DBusMessageIter(L);
} else {
lua_settop(L, 2);

/* remove possible reference to previously referred message */
unref_dbus_message_iter(L);
}
sub = luaL_checkudata(L, 2, DBUS_MESSAGE_ITER_METATABLE);

dbus_message_iter_recurse(iter, sub);
dbus_message_iter_recurse(&iter->iter, &sub->iter);
sub->message = iter->message;
dbus_message_ref(sub->message);

return 1;
}
Expand Down Expand Up @@ -286,10 +306,10 @@ static int ldbus_message_iter_append_basic(lua_State *L) {
}

static int ldbus_message_iter_open_container(lua_State *L) {
DBusMessageIter *iter = luaL_checkudata(L, 1, DBUS_MESSAGE_ITER_METATABLE);
lDBusMessageIter *iter = luaL_checkudata(L, 1, DBUS_MESSAGE_ITER_METATABLE);
int argtype;
const char *contained_signature;
DBusMessageIter *sub;
lDBusMessageIter *sub;
if (lua_type(L, 2) != LUA_TSTRING || lua_rawlen(L, 2) != 1) {
return luaL_argerror(L, 2, lua_pushfstring(L, "character expected, got %s", luaL_typename(L, 2)));
}
Expand All @@ -299,13 +319,19 @@ static int ldbus_message_iter_open_container(lua_State *L) {
push_DBusMessageIter(L);
} else {
lua_settop(L, 4);

/* remove possible reference to previously referred message */
unref_dbus_message_iter(L);
}
sub = luaL_checkudata(L, -1, DBUS_MESSAGE_ITER_METATABLE);

if (!dbus_message_iter_open_container(iter, argtype, contained_signature, sub)) {
if (!dbus_message_iter_open_container(&iter->iter, argtype, contained_signature, &sub->iter)) {
return luaL_error(L, LDBUS_NO_MEMORY);
}

sub->message = iter->message;
dbus_message_ref(sub->message);

return 1;
}

Expand Down Expand Up @@ -334,7 +360,8 @@ LDBUS_INTERNAL int push_DBusMessageIter(lua_State *L) {
{ NULL, NULL }
};

lua_newuserdata(L, sizeof(DBusMessageIter));
lDBusMessageIter *iter = lua_newuserdata(L, sizeof(lDBusMessageIter));
iter->message = NULL;

if (luaL_newmetatable(L, DBUS_MESSAGE_ITER_METATABLE)) {
luaL_newlib(L, methods);
Expand All @@ -343,6 +370,9 @@ LDBUS_INTERNAL int push_DBusMessageIter(lua_State *L) {
lua_pushcfunction(L, tostring);
lua_setfield(L, -2, "__tostring");

lua_pushcfunction(L, unref_dbus_message_iter);
lua_setfield(L, -2, "__gc");

lua_pushstring(L, "DBusMessageIter");
lua_setfield(L, -2, "__udtype");
}
Expand Down
14 changes: 14 additions & 0 deletions src/message_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,23 @@

#include "ldbus.h"

typedef struct {
/* This must be the first member, thus for binding functions that doesn't
care about the underlying DBusMessage, this structure could be safely
referred with a DBusMessageIter pointer.
*/
DBusMessageIter iter;
/* The message which this iterator refers to. NULL if this iterator hasn't
been initialized with a message.
We need to unref it when the iterator is garbagecollected.
*/
DBusMessage *message;
} lDBusMessageIter;

#define DBUS_MESSAGE_ITER_METATABLE "ldbus_DBusMessageIter"

LDBUS_INTERNAL int push_DBusMessageIter(lua_State *L);
LDBUS_INTERNAL void load_dbus_message_iter(lua_State *L);
LDBUS_INTERNAL int unref_dbus_message_iter(lua_State *L);

#endif

0 comments on commit 3afdbee

Please sign in to comment.