diff --git a/include/haproxy/list.h b/include/haproxy/list.h index c2fcdfbc6..95cc78a75 100644 --- a/include/haproxy/list.h +++ b/include/haproxy/list.h @@ -284,10 +284,11 @@ static __inline void watcher_attach(struct watcher *w, void *target) MT_LIST_APPEND(list, &w->el); } -/* Untracks target via watcher. Invalid if is not attached first. */ +/* Untracks target via watcher. Does nothing if is not attached */ static __inline void watcher_detach(struct watcher *w) { - BUG_ON_HOT(!MT_LIST_INLIST(&w->el)); + if (!MT_LIST_INLIST(&w->el)) + return; *w->pptr = NULL; MT_LIST_DELETE(&w->el); } diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c index cf8738e50..3e1cdef69 100644 --- a/src/hlua_fcn.c +++ b/src/hlua_fcn.c @@ -1913,6 +1913,21 @@ int hlua_listable_servers_pairs_iterator(lua_State *L) return 2; } +/* ensure proper cleanup for listable_servers_pairs */ +int hlua_listable_servers_pairs_gc(lua_State *L) +{ + struct hlua_server_list_iterator_context *ctx; + + ctx = lua_touserdata(L, 1); + + /* we need to make sure that the watcher leaves in detached state even + * if the iterator was interrupted (ie: "break" from the loop), else + * the server watcher list will become corrupted + */ + watcher_detach(&ctx->srv_watch); + return 0; +} + /* init the iterator context, return iterator function * with context as closure. The only argument is a * server list object. @@ -1925,6 +1940,12 @@ int hlua_listable_servers_pairs(lua_State *L) hlua_srv_list = hlua_check_server_list(L, 1); ctx = lua_newuserdata(L, sizeof(*ctx)); + + /* add gc metamethod to the newly created userdata */ + lua_newtable(L); + hlua_class_function(L, "__gc", hlua_listable_servers_pairs_gc); + lua_setmetatable(L, -2); + ctx->px = hlua_srv_list->px; ctx->next = NULL; watcher_init(&ctx->srv_watch, &ctx->next, offsetof(struct server, watcher_list));