ping
On Wed, 2021-09-01 at 22:51 +0200, Martijn van Duren wrote:
> Bluhm asked me to rethink the freeing strategy.
> Here's the end result.
>
> On Mon, 2021-08-30 at 12:03 +0200, Martijn van Duren wrote:
> > 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 1 Sep 2021 20:51:09 -0000
> @@ -270,10 +270,12 @@ agentx_reset(struct agentx *ax)
> struct agentx_session *axs, *tsas;
> struct agentx_request *axr;
> struct agentx_get *axg;
> + int axfree = ax->ax_free;
>
> ax_free(ax->ax_ax);
> ax->ax_ax = NULL;
> ax->ax_fd = -1;
> + ax->ax_free = 1;
>
> ax->ax_cstate = AX_CSTATE_CLOSE;
>
> @@ -289,52 +291,52 @@ agentx_reset(struct agentx *ax)
> TAILQ_REMOVE(&(ax->ax_getreqs), axg, axg_ax_getreqs);
> }
>
> - if (ax->ax_dstate == AX_DSTATE_CLOSE) {
> - agentx_free_finalize(ax);
> - return;
> - }
> + if (ax->ax_dstate == AX_DSTATE_OPEN)
> + agentx_start(ax);
>
> - agentx_start(ax);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> void
> agentx_free(struct agentx *ax)
> {
> struct agentx_session *axs, *tsas;
> + int axfree;
>
> if (ax == NULL)
> return;
>
> - if (ax->ax_dstate == AX_DSTATE_CLOSE) {
> -/* Malloc throws abort on invalid pointers as well */
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> + /* Malloc throws abort on invalid pointers as well */
> + if (ax->ax_dstate == AX_DSTATE_CLOSE)
> agentx_log_ax_fatalx(ax, "%s: double free", __func__);
> - }
> ax->ax_dstate = AX_DSTATE_CLOSE;
>
> - if (!TAILQ_EMPTY(&(ax->ax_sessions))) {
> - TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions,
> - tsas) {
> - if (axs->axs_dstate != AX_DSTATE_CLOSE)
> - agentx_session_free(axs);
> - }
> - } else
> + TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, tsas) {
> + if (axs->axs_dstate != AX_DSTATE_CLOSE)
> + agentx_session_free(axs);
> + }
> + if (!axfree)
> agentx_free_finalize(ax);
> }
>
> static void
> agentx_free_finalize(struct agentx *ax)
> {
> -#ifdef AX_DEBUG
> - if (ax->ax_dstate != AX_DSTATE_CLOSE)
> - agentx_log_ax_fatalx(ax, "%s: agentx not closing",
> - __func__);
> - if (!TAILQ_EMPTY(&(ax->ax_sessions)))
> - agentx_log_ax_fatalx(ax, "%s: agentx still has sessions",
> - __func__);
> - if (!RB_EMPTY(&(ax->ax_requests)))
> - agentx_log_ax_fatalx(ax,
> - "%s: agentx still has pending requests", __func__);
> -#endif
> + struct agentx_session *axs, *taxs;
> +
> + ax->ax_free = 0;
> +
> + TAILQ_FOREACH_SAFE(axs, &(ax->ax_sessions), axs_ax_sessions, taxs)
> + agentx_session_free_finalize(axs);
> +
> + if (!TAILQ_EMPTY(&(ax->ax_sessions)) ||
> + !RB_EMPTY(&(ax->ax_requests)) ||
> + ax->ax_dstate != AX_DSTATE_CLOSE)
> + return;
>
> ax_free(ax->ax_ax);
> ax->ax_nofd(ax, ax->ax_cookie, 1);
> @@ -477,6 +479,7 @@ agentx_session_close_finalize(struct ax_
> struct agentx_session *axs = cookie;
> struct agentx *ax = axs->axs_ax;
> struct agentx_context *axc, *tsac;
> + int axfree = ax->ax_free;
>
> #ifdef AX_DEBUG
> if (axs->axs_cstate != AX_CSTATE_WAITCLOSE)
> @@ -492,19 +495,19 @@ agentx_session_close_finalize(struct ax_
> }
>
> axs->axs_cstate = AX_CSTATE_CLOSE;
> + ax->ax_free = 1;
>
> agentx_log_axs_info(axs, "closed");
>
> TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, tsac)
> agentx_context_reset(axc);
>
> - if (axs->axs_dstate == AX_DSTATE_CLOSE)
> - agentx_session_free_finalize(axs);
> - else {
> - if (ax->ax_cstate == AX_CSTATE_OPEN)
> - if (agentx_session_start(axs) == -1)
> - return -1;
> - }
> + if (ax->ax_cstate == AX_CSTATE_OPEN &&
> + axs->axs_dstate == AX_DSTATE_OPEN)
> + agentx_session_start(axs);
> + if (!axfree)
> + agentx_free_finalize(ax);
> +
> return 0;
> }
>
> @@ -512,10 +515,16 @@ void
> agentx_session_free(struct agentx_session *axs)
> {
> struct agentx_context *axc, *tsac;
> + struct agentx *ax;
> + int axfree;
>
> if (axs == NULL)
> return;
>
> + ax = axs->axs_ax;
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> if (axs->axs_dstate == AX_DSTATE_CLOSE)
> agentx_log_axs_fatalx(axs, "%s: double free", __func__);
>
> @@ -529,44 +538,45 @@ agentx_session_free(struct agentx_sessio
> agentx_context_free(axc);
> }
>
> - if (axs->axs_cstate == AX_CSTATE_CLOSE)
> - agentx_session_free_finalize(axs);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> static void
> agentx_session_free_finalize(struct agentx_session *axs)
> {
> struct agentx *ax = axs->axs_ax;
> + struct agentx_context *axc, *taxc;
>
> -#ifdef AX_DEBUG
> - if (axs->axs_cstate != AX_CSTATE_CLOSE)
> - agentx_log_axs_fatalx(axs, "%s: free without closing",
> - __func__);
> - if (!TAILQ_EMPTY(&(axs->axs_contexts)))
> - agentx_log_axs_fatalx(axs,
> - "%s: agentx still has contexts", __func__);
> -#endif
> + TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, taxc)
> + agentx_context_free_finalize(axc);
> +
> + if (!TAILQ_EMPTY(&(axs->axs_contexts)) ||
> + axs->axs_cstate != AX_CSTATE_CLOSE ||
> + axs->axs_dstate != AX_DSTATE_CLOSE)
> + return;
>
> TAILQ_REMOVE(&(ax->ax_sessions), axs, axs_ax_sessions);
> free(axs->axs_descr.aos_string);
> free(axs);
> -
> - if (TAILQ_EMPTY(&(ax->ax_sessions)) && ax->ax_dstate == AX_DSTATE_CLOSE)
> - agentx_free_finalize(ax);
> }
>
> static void
> agentx_session_reset(struct agentx_session *axs)
> {
> struct agentx_context *axc, *tsac;
> + struct agentx *ax = axs->axs_ax;
> + int axfree = ax->ax_free;
> +
> + ax->ax_free = 1;
>
> axs->axs_cstate = AX_CSTATE_CLOSE;
>
> TAILQ_FOREACH_SAFE(axc, &(axs->axs_contexts), axc_axs_contexts, tsac)
> agentx_context_reset(axc);
>
> - if (axs->axs_dstate == AX_DSTATE_CLOSE)
> - agentx_session_free_finalize(axs);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> struct agentx_context *
> @@ -714,15 +724,20 @@ static void
> agentx_context_free_finalize(struct agentx_context *axc)
> {
> struct agentx_session *axs = axc->axc_axs;
> + struct agentx_region *axr, *taxr;
> + struct agentx_agentcaps *axa, *taxa;
> +
> + TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, taxa)
> + agentx_agentcaps_free_finalize(axa);
> + TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, taxr)
> + agentx_region_free_finalize(axr);
>
> -#ifdef AX_DEBUG
> - if (axc->axc_dstate != AX_DSTATE_CLOSE)
> - agentx_log_axc_fatalx(axc, "%s: unexpected context free",
> - __func__);
> -#endif
> if (!TAILQ_EMPTY(&(axc->axc_regions)) ||
> - !TAILQ_EMPTY(&(axc->axc_agentcaps)))
> + !TAILQ_EMPTY(&(axc->axc_agentcaps)) ||
> + axc->axc_cstate != AX_CSTATE_CLOSE ||
> + axc->axc_dstate != AX_DSTATE_CLOSE)
> return;
> +
> TAILQ_REMOVE(&(axs->axs_contexts), axc, axc_axs_contexts);
> free(axc->axc_name.aos_string);
> free(axc);
> @@ -733,6 +748,10 @@ agentx_context_reset(struct agentx_conte
> {
> struct agentx_agentcaps *axa, *tsaa;
> struct agentx_region *axr, *tsar;
> + struct agentx *ax = axc->axc_axs->axs_ax;
> + int axfree = ax->ax_free;
> +
> + ax->ax_free = 1;
>
> axc->axc_cstate = AX_CSTATE_CLOSE;
> axc->axc_sysuptimespec.tv_sec = 0;
> @@ -743,8 +762,8 @@ agentx_context_reset(struct agentx_conte
> TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, tsar)
> agentx_region_reset(axr);
>
> - if (axc->axc_dstate == AX_DSTATE_CLOSE)
> - agentx_context_free_finalize(axc);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> struct agentx_agentcaps *
> @@ -883,6 +902,7 @@ agentx_agentcaps_close_finalize(struct a
> struct agentx_context *axc = axa->axa_axc;
> struct agentx_session *axs = axc->axc_axs;
> struct agentx *ax = axs->axs_ax;
> + int axfree = ax->ax_free;
>
> #ifdef AX_DEBUG
> if (axa->axa_cstate != AX_CSTATE_WAITCLOSE)
> @@ -899,41 +919,43 @@ agentx_agentcaps_close_finalize(struct a
> }
>
> axa->axa_cstate = AX_CSTATE_CLOSE;
> + ax->ax_free = 1;
>
> agentx_log_axc_info(axc, "agentcaps %s: closed",
> ax_oid2string(&(axa->axa_oid)));
>
> - if (axa->axa_dstate == AX_DSTATE_CLOSE) {
> - agentx_agentcaps_free_finalize(axa);
> - return 0;
> - } else {
> - if (axc->axc_cstate == AX_CSTATE_OPEN) {
> - if (agentx_agentcaps_start(axa) == -1)
> - return -1;
> - }
> - }
> + if (axc->axc_cstate == AX_CSTATE_OPEN &&
> + axa->axa_dstate == AX_DSTATE_OPEN)
> + agentx_agentcaps_start(axa);
> +
> + if (!axfree)
> + agentx_free_finalize(ax);
> return 0;
> }
>
> void
> agentx_agentcaps_free(struct agentx_agentcaps *axa)
> {
> + struct agentx *ax = axa->axa_axc->axc_axs->axs_ax;
> + int axfree;
> +
> if (axa == NULL)
> return;
>
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> if (axa->axa_dstate == AX_DSTATE_CLOSE)
> agentx_log_axc_fatalx(axa->axa_axc, "%s: double free",
> __func__);
>
> axa->axa_dstate = AX_DSTATE_CLOSE;
>
> - if (axa->axa_cstate == AX_CSTATE_OPEN) {
> - if (agentx_agentcaps_close(axa) == -1)
> - return;
> - }
> + if (axa->axa_cstate == AX_CSTATE_OPEN)
> + agentx_agentcaps_close(axa);
>
> - if (axa->axa_cstate == AX_CSTATE_CLOSE)
> - agentx_agentcaps_free_finalize(axa);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> static void
> @@ -941,27 +963,24 @@ agentx_agentcaps_free_finalize(struct ag
> {
> struct agentx_context *axc = axa->axa_axc;
>
> -#ifdef AX_DEBUG
> if (axa->axa_dstate != AX_DSTATE_CLOSE ||
> axa->axa_cstate != AX_CSTATE_CLOSE)
> - agentx_log_axc_fatalx(axc, "%s: unexpected free", __func__);
> -#endif
> + return;
>
> TAILQ_REMOVE(&(axc->axc_agentcaps), axa, axa_axc_agentcaps);
> free(axa->axa_descr.aos_string);
> free(axa);
> -
> - if (axc->axc_dstate == AX_DSTATE_CLOSE)
> - agentx_context_free_finalize(axc);
> }
>
> static void
> agentx_agentcaps_reset(struct agentx_agentcaps *axa)
> {
> + struct agentx *ax = axa->axa_axc->axc_axs->axs_ax;
> +
> axa->axa_cstate = AX_CSTATE_CLOSE;
>
> - if (axa->axa_dstate == AX_DSTATE_CLOSE)
> - agentx_agentcaps_free_finalize(axa);
> + if (!ax->ax_free)
> + agentx_free_finalize(ax);
> }
>
> struct agentx_region *
> @@ -1166,6 +1185,7 @@ agentx_region_close_finalize(struct ax_p
> struct agentx_context *axc = axr->axr_axc;
> struct agentx_session *axs = axc->axc_axs;
> struct agentx *ax = axs->axs_ax;
> + int axfree = ax->ax_free;
>
> #ifdef AX_DEBUG
> if (axr->axr_cstate != AX_CSTATE_WAITCLOSE)
> @@ -1181,21 +1201,19 @@ agentx_region_close_finalize(struct ax_p
> return -1;
> }
>
> + ax->ax_free = 1;
> axr->axr_priority = AX_PRIORITY_DEFAULT;
> axr->axr_cstate = AX_CSTATE_CLOSE;
>
> agentx_log_axc_info(axc, "region %s: closed",
> ax_oid2string(&(axr->axr_oid)));
>
> - if (axr->axr_dstate == AX_DSTATE_CLOSE) {
> - agentx_region_free_finalize(axr);
> - return 0;
> - } else {
> - if (axc->axc_cstate == AX_CSTATE_OPEN) {
> - if (agentx_region_start(axr) == -1)
> - return -1;
> - }
> - }
> + if (axc->axc_cstate == AX_CSTATE_OPEN &&
> + axr->axr_dstate == AX_DSTATE_OPEN)
> + agentx_region_start(axr);
> +
> + if (!axfree)
> + agentx_free_finalize(ax);
> return 0;
> }
>
> @@ -1204,10 +1222,16 @@ agentx_region_free(struct agentx_region
> {
> struct agentx_index *axi, *tsai;
> struct agentx_object *axo, *tsao;
> + struct agentx *ax;
> + int axfree;
>
> if (axr == NULL)
> return;
>
> + ax = axr->axr_axc->axc_axs->axs_ax;
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> if (axr->axr_dstate == AX_DSTATE_CLOSE)
> agentx_log_axc_fatalx(axr->axr_axc, "%s: double free",
> __func__);
> @@ -1224,37 +1248,33 @@ agentx_region_free(struct agentx_region
> agentx_object_free(axo);
> }
>
> - if (axr->axr_cstate == AX_CSTATE_OPEN) {
> - if (agentx_region_close(axr) == -1)
> - return;
> - }
> + if (axr->axr_cstate == AX_CSTATE_OPEN)
> + agentx_region_close(axr);
>
> - if (axr->axr_cstate == AX_CSTATE_CLOSE)
> - agentx_region_free_finalize(axr);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> static void
> agentx_region_free_finalize(struct agentx_region *axr)
> {
> struct agentx_context *axc = axr->axr_axc;
> + struct agentx_index *axi, *taxi;
> + struct agentx_object *axo, *taxo;
>
> -#ifdef AX_DEBUG
> - if (axr->axr_dstate != AX_DSTATE_CLOSE)
> - agentx_log_axc_fatalx(axc, "%s: unexpected free", __func__);
> -#endif
> + TAILQ_FOREACH_SAFE(axo, &(axr->axr_objects), axo_axr_objects, taxo)
> + agentx_object_free_finalize(axo);
> + TAILQ_FOREACH_SAFE(axi, &(axr->axr_indices), axi_axr_indices, taxi)
> + agentx_index_free_finalize(axi);
>
> if (!TAILQ_EMPTY(&(axr->axr_indices)) ||
> - !TAILQ_EMPTY(&(axr->axr_objects)))
> - return;
> -
> - if (axr->axr_cstate != AX_CSTATE_CLOSE)
> + !TAILQ_EMPTY(&(axr->axr_objects)) ||
> + axr->axr_cstate != AX_CSTATE_CLOSE ||
> + axr->axr_dstate != AX_DSTATE_CLOSE)
> return;
>
> TAILQ_REMOVE(&(axc->axc_regions), axr, axr_axc_regions);
> free(axr);
> -
> - if (axc->axc_dstate == AX_DSTATE_CLOSE)
> - agentx_context_free_finalize(axc);
> }
>
> static void
> @@ -1262,17 +1282,20 @@ agentx_region_reset(struct agentx_region
> {
> struct agentx_index *axi, *tsai;
> struct agentx_object *axo, *tsao;
> + struct agentx *ax = axr->axr_axc->axc_axs->axs_ax;
> + int axfree = ax->ax_free;
>
> axr->axr_cstate = AX_CSTATE_CLOSE;
> axr->axr_priority = AX_PRIORITY_DEFAULT;
> + ax->ax_free = 1;
>
> 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)
> agentx_object_reset(axo);
>
> - if (axr->axr_dstate == AX_DSTATE_CLOSE)
> - agentx_region_free_finalize(axr);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> struct agentx_index *
> @@ -1739,10 +1762,16 @@ agentx_index_free(struct agentx_index *a
> {
> size_t i;
> struct agentx_object *axo;
> + struct agentx *ax;
> + int axfree;
>
> if (axi == NULL)
> return;
>
> + ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> if (axi->axi_dstate == AX_DSTATE_CLOSE)
> agentx_log_axc_fatalx(axi->axi_axr->axr_axc,
> "%s: double free", __func__);
> @@ -1761,8 +1790,8 @@ agentx_index_free(struct agentx_index *a
>
> if (axi->axi_cstate == AX_CSTATE_OPEN)
> (void) agentx_index_close(axi);
> - else if (axi->axi_cstate == AX_CSTATE_CLOSE)
> - agentx_index_free_finalize(axi);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> static void
> @@ -1770,33 +1799,26 @@ agentx_index_free_finalize(struct agentx
> {
> struct agentx_region *axr = axi->axi_axr;
>
> -#ifdef AX_DEBUG
> - if (axi->axi_dstate != AX_DSTATE_CLOSE)
> - agentx_log_axc_fatalx(axr->axr_axc, "%s: unexpected free",
> - __func__);
> - if (axi->axi_cstate != AX_CSTATE_CLOSE)
> - agentx_log_axc_fatalx(axr->axr_axc,
> - "%s: free without deallocating", __func__);
> -#endif
> -
> - if (axi->axi_objectlen != 0)
> + if (axi->axi_cstate != AX_CSTATE_CLOSE ||
> + axi->axi_dstate != AX_DSTATE_CLOSE ||
> + axi->axi_objectlen != 0)
> return;
>
> TAILQ_REMOVE(&(axr->axr_indices), axi, axi_axr_indices);
> ax_varbind_free(&(axi->axi_vb));
> free(axi->axi_object);
> free(axi);
> - if (axr->axr_dstate == AX_DSTATE_CLOSE)
> - agentx_region_free_finalize(axr);
> }
>
> static void
> agentx_index_reset(struct agentx_index *axi)
> {
> + struct agentx *ax = axi->axi_axr->axr_axc->axc_axs->axs_ax;
> +
> axi->axi_cstate = AX_CSTATE_CLOSE;
>
> - if (axi->axi_dstate == AX_DSTATE_CLOSE)
> - agentx_index_free_finalize(axi);
> + if (!ax->ax_free)
> + agentx_free_finalize(ax);
> }
>
> static int
> @@ -1842,6 +1864,7 @@ agentx_index_close_finalize(struct ax_pd
> struct agentx_session *axs = axc->axc_axs;
> struct agentx *ax = axs->axs_ax;
> struct ax_pdu_response *resp = &(pdu->ap_payload.ap_response);
> + int axfree = ax->ax_free;
>
> #ifdef AX_DEBUG
> if (axi->axi_cstate != AX_CSTATE_WAITCLOSE)
> @@ -1895,16 +1918,17 @@ agentx_index_close_finalize(struct ax_pd
> }
>
> axi->axi_cstate = AX_CSTATE_CLOSE;
> + ax->ax_free = 1;
>
> agentx_log_axc_info(axc, "index %s: deallocated",
> ax_oid2string(&(axi->axi_vb.avb_oid)));
>
> - if (axi->axi_dstate == AX_DSTATE_CLOSE) {
> - agentx_index_free_finalize(axi);
> - } else if (axr->axr_cstate == AX_CSTATE_OPEN) {
> - if (agentx_index_start(axi) == -1)
> - return -1;
> - }
> + if (axr->axr_cstate == AX_CSTATE_OPEN &&
> + axi->axi_dstate == AX_DSTATE_OPEN)
> + agentx_index_start(axi);
> +
> + if (!axfree)
> + agentx_free_finalize(ax);
> return 0;
> }
>
> @@ -2198,8 +2222,6 @@ agentx_object_finalize(struct ax_pdu *pd
> agentx_log_axc_info(axc, "object %s (%s %s): %s",
> oids, flags ? "instance" : "region", ax_oid2string(&oid),
> ax_error2string(pdu->ap_payload.ap_response.ap_error));
> - if (axo->axo_dstate == AX_DSTATE_CLOSE)
> - return agentx_object_close_finalize(NULL, axo);
> return 0;
> }
> axo->axo_cstate = AX_CSTATE_OPEN;
> @@ -2227,15 +2249,18 @@ agentx_object_lock(struct agentx_object
> static void
> agentx_object_unlock(struct agentx_object *axo)
> {
> + struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
> +
> #ifdef AX_DEBUG
> if (axo->axo_lock == 0)
> agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
> "%s: axo_lock == 0", __func__);
> #endif
> axo->axo_lock--;
> - if (axo->axo_lock == 0 && axo->axo_dstate == AX_DSTATE_CLOSE &&
> - axo->axo_cstate == AX_CSTATE_CLOSE)
> - agentx_object_free_finalize(axo);
> + if (axo->axo_lock == 0) {
> + if (!ax->ax_free)
> + agentx_free_finalize(ax);
> + }
> }
>
> static int
> @@ -2316,6 +2341,7 @@ agentx_object_close_finalize(struct ax_p
> char oids[1024];
> uint8_t flags = 1;
> size_t i;
> + int axfree = ax->ax_free;
>
> #ifdef AX_DEBUG
> if (axo->axo_cstate != AX_CSTATE_WAITCLOSE)
> @@ -2355,13 +2381,13 @@ agentx_object_close_finalize(struct ax_p
> flags ? "instance" : "region", ax_oid2string(&oid));
> }
>
> - if (axo->axo_dstate == AX_DSTATE_CLOSE)
> - agentx_object_free_finalize(axo);
> - else {
> - if (axr->axr_cstate == AX_CSTATE_OPEN)
> - if (agentx_object_start(axo) == -1)
> - return -1;
> - }
> + ax->ax_free = 1;
> + if (axr->axr_cstate == AX_CSTATE_OPEN &&
> + axo->axo_dstate == AX_DSTATE_OPEN)
> + agentx_object_start(axo);
> +
> + if (!axfree)
> + agentx_free_finalize(ax);
>
> return 0;
> }
> @@ -2369,21 +2395,26 @@ agentx_object_close_finalize(struct ax_p
> void
> agentx_object_free(struct agentx_object *axo)
> {
> + struct agentx *ax;
> + int axfree;
> +
> if (axo == NULL)
> return;
>
> + ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
> + axfree = ax->ax_free;
> + ax->ax_free = 1;
> +
> if (axo->axo_dstate == AX_DSTATE_CLOSE)
> agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
> "%s: double free", __func__);
>
> axo->axo_dstate = AX_DSTATE_CLOSE;
>
> - if (axo->axo_cstate == AX_CSTATE_OPEN) {
> - if (agentx_object_close(axo) == -1)
> - return;
> - }
> - if (axo->axo_cstate == AX_CSTATE_CLOSE)
> - agentx_object_free_finalize(axo);
> + if (axo->axo_cstate == AX_CSTATE_OPEN)
> + agentx_object_close(axo);
> + if (!axfree)
> + agentx_free_finalize(ax);
> }
>
> static void
> @@ -2395,21 +2426,10 @@ agentx_object_free_finalize(struct agent
> size_t i, j;
> int found;
>
> -#ifdef AX_DEBUG
> - if (axo->axo_dstate != AX_DSTATE_CLOSE)
> - agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
> - "%s: unexpected free", __func__);
> -#endif
> -
> - if (axo->axo_lock != 0) {
> -#ifdef AX_DEBUG
> - if (TAILQ_EMPTY(&(ax->ax_getreqs)))
> - agentx_log_axc_fatalx(axo->axo_axr->axr_axc,
> - "%s: %s axo_lock == %u", __func__,
> - ax_oid2string(&(axo->axo_oid)), axo->axo_lock);
> -#endif
> + if (axo->axo_dstate != AX_DSTATE_CLOSE ||
> + axo->axo_cstate != AX_CSTATE_CLOSE ||
> + axo->axo_lock != 0)
> return;
> - }
>
> RB_REMOVE(axc_objects, &(axo->axo_axr->axr_axc->axc_objects), axo);
> TAILQ_REMOVE(&(axo->axo_axr->axr_objects), axo, axo_axr_objects);
> @@ -2429,9 +2449,6 @@ agentx_object_free_finalize(struct agent
> "%s: object not found in index", __func__);
> #endif
> axo->axo_index[i]->axi_objectlen--;
> - if (axo->axo_index[i]->axi_dstate == AX_DSTATE_CLOSE &&
> - axo->axo_index[i]->axi_cstate == AX_CSTATE_CLOSE)
> - agentx_index_free_finalize(axo->axo_index[i]);
> }
>
> free(axo);
> @@ -2440,10 +2457,12 @@ agentx_object_free_finalize(struct agent
> static void
> agentx_object_reset(struct agentx_object *axo)
> {
> + struct agentx *ax = axo->axo_axr->axr_axc->axc_axs->axs_ax;
> +
> axo->axo_cstate = AX_CSTATE_CLOSE;
>
> - if (axo->axo_dstate == AX_DSTATE_CLOSE)
> - agentx_object_free_finalize(axo);
> + if (!ax->ax_free)
> + agentx_free_finalize(ax);
> }
>
> static int
> Index: agentx_internal.h
> ===================================================================
> RCS file: /cvs/src/lib/libagentx/agentx_internal.h,v
> retrieving revision 1.2
> diff -u -p -r1.2 agentx_internal.h
> --- agentx_internal.h 26 Oct 2020 16:02:16 -0000 1.2
> +++ agentx_internal.h 1 Sep 2021 20:51:09 -0000
> @@ -38,6 +38,7 @@ struct agentx {
> int ax_fd;
> enum agentx_cstate ax_cstate;
> enum agentx_dstate ax_dstate;
> + int ax_free; /* Freeing already planned */
> struct ax *ax_ax;
> TAILQ_HEAD(, agentx_session) ax_sessions;
> TAILQ_HEAD(, agentx_get) ax_getreqs;
>