| Author | Andy Green <andy@warmcat.com> 2026-09-06 07:56 UTC | | Committer | Andy Green <andy@warmcat.com> 2026-09-06 07:56 UTC | | Tree | 7ebe087e3ba0f2dd55a5fc7a02a25d1c6060f9bc Raw Patch | | | server: free the parse lwsac on every websrvss_ws_rx exit, fixes F-012 | server: free the parse lwsac on every websrvss_ws_rx exit, fixes F-012
websrvss_ws_rx() allocates every parsed object into the stack-local
a.ac (lwsac_use_zero per object inside lws-struct-lejp), so it must be
freed exactly once per call; but most handler arms ended in break with
no free (TASKRESET, TASKREMOVEALLTRIES, TASKPAUSE, TASKRESUME,
TASKKILL, TASKREBUILDLASTSTEP, TASKCANCEL, VIEWERCOUNT, REBUILD) and
every soft_error path (the sais_validate_id rejections) returned
without freeing either. sai-web forwards a com.warmcat.sai.viewercount
on every browser connect and disconnect, so unauthenticated flapping
against the public browse endpoint grows sai-server's heap without
bound.
Free a.ac once at the function exits (normal and soft_error), matching
the single-exit discipline saiw_ws_json_rx_browser() already uses, and
drop the now-redundant per-case frees. No handler retains pointers
into the ac: everything long-lived is deep-copied on queueing.
|
diff --git a/src/server/s-ws-web.c b/src/server/s-ws-web.c
index 3416e5a..4a784df 100644
--- a/src/server/s-ws-web.c
+++ b/src/server/s-ws-web.c
@@ -537,7 +537,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
if (r)
lwsl_ss_err(m->ss, "eventreset failed");
- lwsac_free(&a.ac);
break;
case SAIS_WS_WEBSRV_RX_PLATRESET: {
@@ -549,7 +548,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
r = sais_plat_reset(m->vhd, pr->event_uuid, pr->platform);
if (r)
lwsl_ss_err(m->ss, "platreset failed");
- lwsac_free(&a.ac);
break;
}
case SAIS_WS_WEBSRV_RX_PCON_CONTROL:
@@ -579,7 +577,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
if (!count)
lwsl_warn("%s: No sai-power connections found to forward control to!\n", __func__);
- lwsac_free(&a.ac);
break;
}
@@ -593,7 +590,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
r = sais_event_delete(m->vhd, ei->event_hash);
if (r)
lwsl_ss_err(m->ss, "event delete failed");
- lwsac_free(&a.ac);
break;
case SAIS_WS_WEBSRV_RX_TASKCANCEL:
@@ -653,7 +649,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
if (!sp) {
lwsl_info("%s: unknown builder %s for rebuild\n",
__func__, reb->builder_name);
- lwsac_free(&a.ac);
break;
}
@@ -697,7 +692,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
}
} lws_end_foreach_dll(p);
- lwsac_free(&a.ac);
break;
}
case SAIS_WS_WEBSRV_RX_OPENSHELL:
@@ -715,7 +709,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
if (sais_validate_builder_name(os->builder_name)) {
lwsl_notice("%s: OPENSHELL bad builder name '%s'\n",
__func__, os->builder_name);
- lwsac_free(&a.ac);
break;
}
@@ -752,7 +745,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
sais_platforms_with_tasks_pending(m->vhd);
- lwsac_free(&a.ac);
break;
}
@@ -762,7 +754,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
if (sais_validate_id(cs->task_uuid, SAI_TASKID_LEN)) {
lwsl_notice("%s: CLOSESHELL bad task_uuid\n", __func__);
- lwsac_free(&a.ac);
break;
}
@@ -785,7 +776,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
sais_task_cancel(m->vhd, cs->task_uuid, 0, 0);
sais_platforms_with_tasks_pending(m->vhd);
- lwsac_free(&a.ac);
break;
}
@@ -802,7 +792,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
sais_validate_builder_name(pd->builder_name)) {
lwsl_notice("%s: PTYDATA bad task_uuid/builder\n",
__func__);
- lwsac_free(&a.ac);
break;
}
@@ -828,7 +817,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
}
} lws_end_foreach_dll(d);
- lwsac_free(&a.ac);
break;
}
@@ -855,7 +843,6 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
}
} lws_end_foreach_dll(p);
- lwsac_free(&a.ac);
break;
}
@@ -882,16 +869,19 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
/* Force broadcast of updated builders list */
sais_list_builders(m->vhd);
- lwsac_free(&a.ac);
break;
}
}
+ lwsac_free(&a.ac);
+
return 0;
soft_error:
lwsl_warn("%s: soft error\n", __func__);
+ lwsac_free(&a.ac);
+
return 0;
}
|