Free OtaContext-owned buffers when the context is torn down

OtaContext owns serve_buf, serve_self_leaves and serve_self_proof as raw
malloc'd pointers, and nothing freed them on teardown: self-serve only frees
them when it re-allocates, and reset_session() does not touch them. That was
harmless while the context was a permanent .bss singleton, but both dynamic
storage modes destroy it between operations - OTA_HEAP_CONTEXT deletes it,
and the Companion's borrowed queue runs ~OtaContext() in place. A self-serving
node reaches release with both self-serve buffers populated, so every
acquire/release cycle leaked them.

Give OtaContext a destructor that releases what it owns, and delete the copy
operations so the raw pointers cannot be double-freed.
This commit is contained in:
MUSTARDTIGERFPV committed 2026-09-09 01:24:00 -07:00
1 parent 0d42d3c8e1
commit 1257ea4dc5
1 file changed
+16
+16
View File
@@ -144,6 +144,22 @@ struct OtaContext {
// count (the manager's fixed 4 KiB scratch covers <=1024 blocks, about 2 MiB at the new default).
uint8_t* serve_self_leaves = nullptr;
uint8_t* serve_self_proof = nullptr;
// These raw buffers are owned by the context and are otherwise only freed
// when self-serve re-allocates them. A dynamic-storage build destroys the
// context between operations (OTA_HEAP_CONTEXT deletes it; the Companion's
// borrowed queue runs ~OtaContext() in place), so teardown has to release
// them or every acquire/release cycle leaks. A self-serving node reaches
// release with both buffers populated, so this is the normal path, not an
// edge case.
~OtaContext() {
releaseServeBuffer(); // no-op where serve_buf is a fixed array
free(serve_self_leaves);
free(serve_self_proof);
}
OtaContext() = default;
OtaContext(const OtaContext&) = delete; // would double-free above
OtaContext& operator=(const OtaContext&) = delete;
uint8_t serve_self_manifest[MOTA_MFL]; // fixed-layout full+unsigned manifest-minus-leaves (197 B)
ApplyState apply_st; // pending apply (P6)