]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: httpclient/lua: crash when the lua task timeout before the httpclient
authorWilliam Lallemand <wlallemand@haproxy.org>
Thu, 20 Oct 2022 08:57:28 +0000 (10:57 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Thu, 20 Oct 2022 16:47:15 +0000 (18:47 +0200)
When the lua task finished  before the httpclient that are associated to
it, there is a risk that the httpclient try to task_wakeup() the lua
task which does not exist anymore.

To fix this issue the httpclient used in a lua task are stored in a
list, and the httpclient are destroyed at the end of the lua task.

Must be backported in 2.5 and 2.6.

include/haproxy/hlua-t.h
src/hlua.c

index 82204fe387b8e90462cf4302cb9ece348edf224a..bc8c8df73db62091833ea26d0b464286a909fdc7 100644 (file)
@@ -111,6 +111,7 @@ struct hlua {
        struct task *task; /* The task associated with the lua stack execution.
                              We must wake this task to continue the task execution */
        struct list com; /* The list head of the signals attached to this task. */
+       struct list hc_list;  /* list of httpclient associated to this lua task */
        struct ebpt_node node;
        int gc_count;  /* number of items which need a GC */
 };
@@ -198,6 +199,7 @@ struct hlua_httpclient {
        struct httpclient *hc; /* ptr to the httpclient instance */
        size_t sent; /* payload sent */
        luaL_Buffer b; /* buffer used to prepare strings. */
+       struct list by_hlua; /* linked in the current hlua task */
 };
 
 #else /* USE_LUA */
index 70be127f1ac657dba8eea526e36290adf43cf5bd..9b646bc20c5fbc8df29dcbaae7ec0796433be152 100644 (file)
@@ -1248,6 +1248,7 @@ int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already
        lua->wake_time = TICK_ETERNITY;
        lua->state_id = state_id;
        LIST_INIT(&lua->com);
+       LIST_INIT(&lua->hc_list);
        if (!already_safe) {
                if (!SET_SAFE_LJMP_PARENT(lua)) {
                        lua->Tref = LUA_REFNIL;
@@ -1269,6 +1270,20 @@ int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already
        return 1;
 }
 
+/* kill all associated httpclient to this hlua task */
+static void hlua_httpclient_destroy_all(struct hlua *hlua)
+{
+       struct hlua_httpclient *hlua_hc, *back;
+
+       list_for_each_entry_safe(hlua_hc, back, &hlua->hc_list, by_hlua) {
+               if (hlua_hc->hc)
+                       httpclient_stop_and_destroy(hlua_hc->hc);
+               hlua_hc->hc = NULL;
+               LIST_DELETE(&hlua_hc->by_hlua);
+       }
+}
+
+
 /* Used to destroy the Lua coroutine when the attached stream or task
  * is destroyed. The destroy also the memory context. The struct "lua"
  * is not freed.
@@ -1281,6 +1296,9 @@ void hlua_ctx_destroy(struct hlua *lua)
        if (!lua->T)
                goto end;
 
+       /* clean all running httpclient */
+       hlua_httpclient_destroy_all(lua);
+
        /* Purge all the pending signals. */
        notification_purge(&lua->com);
 
@@ -7012,7 +7030,10 @@ __LJMP static int hlua_httpclient_gc(lua_State *L)
 
        hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
 
-       httpclient_stop_and_destroy(hlua_hc->hc);
+       if (hlua_hc->hc)
+               httpclient_stop_and_destroy(hlua_hc->hc);
+
+       LIST_DELETE(&hlua_hc->by_hlua);
 
        hlua_hc->hc = NULL;
 
@@ -7046,6 +7067,8 @@ __LJMP static int hlua_httpclient_new(lua_State *L)
        if (!hlua_hc->hc)
                goto err;
 
+       LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
+
        /* Pop a class stream metatable and affect it to the userdata. */
        lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
        lua_setmetatable(L, -2);