I missed this one before, since apparently it doesn't show up with
MALLOC_OPTIONS set to "S", but it does if it is empty.
This probably effects relayd if the admin has it enabled en then
disables it via a "relayctl reload". However, I'm not able to
reproduce it there and even if it can be triggered, chances of
that happening in real life are slim to none.
I think the comment should explain enough.
OK?
martijn@
Index: agentx.c
===================================================================
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.10
diff -u -p -r1.10 agentx.c
--- agentx.c 2 Jun 2021 08:40:09 -0000 1.10
+++ agentx.c 30 Aug 2021 10:03:08 -0000
@@ -1262,16 +1262,29 @@ agentx_region_reset(struct agentx_region
{
struct agentx_index *axi, *tsai;
struct agentx_object *axo, *tsao;
+ int dofree = 1;
axr->axr_cstate = AX_CSTATE_CLOSE;
axr->axr_priority = AX_PRIORITY_DEFAULT;
- TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, tsai)
+ TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, tsai) {
agentx_index_reset(axi);
- TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, tsao)
+ dofree = 0;
+ }
+ TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, tsao) {
agentx_object_reset(axo);
+ dofree = 0;
+ }
- if (axr->axr_dstate == AX_DSTATE_CLOSE)
+ /*
+ * If there were children they already freed axr for us via
+ * agentx_index_finalize().
+ * This construction is needed because agentx_region_free()
+ * calls the *_close functions on itself and its children, but the close
+ * confirmations might be received out of order and we can't free the
+ * region if there's still children active.
+ */
+ if (dofree && axr->axr_dstate == AX_DSTATE_CLOSE)
agentx_region_free_finalize(axr);
}