Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / src / common / c-sqlite3.c
Author[]Andy Green <andy@warmcat.com> 2026-09-06 07:56 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-09-06 07:56 UTC
Tree7ebe087e3ba0f2dd55a5fc7a02a25d1c6060f9bc   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; }
Page fetched 0s ago, creation time: 1ms (vhost etag hits: 0%, cache hits: 0%)