commit 707d9803c6eeaa3542e2459cc2cf47370f007440
parent 5d6b4317d8f87874a098b8e5e1c513e68d7b40f3
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Mon, 17 Aug 2026 17:00:26 +0200
fix helper cleanup on signal
Diffstat:
1 file changed, 49 insertions(+), 15 deletions(-)
diff --git a/src/mhd/mhd_typst.c b/src/mhd/mhd_typst.c
@@ -362,11 +362,17 @@ pdftk_done_cb (void *cls,
case GNUNET_OS_PROCESS_RUNNING:
/* we should not get this notification */
GNUNET_break (0);
- return;
+ typst_context_fail (tc,
+ TALER_EC_EXCHANGE_GENERIC_PDFTK_CRASH,
+ "pdftk in unexpected state");
+ break;
case GNUNET_OS_PROCESS_STOPPED:
/* Someone is SIGSTOPing our helper!? */
GNUNET_break (0);
- return;
+ typst_context_fail (tc,
+ TALER_EC_EXCHANGE_GENERIC_PDFTK_CRASH,
+ "pdftk was stopped");
+ break;
case GNUNET_OS_PROCESS_EXITED:
if (0 != exit_code)
{
@@ -459,6 +465,33 @@ cancel_async (void *cls)
/**
+ * Fail the typst context @a tc and clean it up asynchronously.
+ *
+ * Note that several stages may fail within the same SIGCHLD batch, in
+ * which case the clean-up task will already have been scheduled by the
+ * first failure; we must not schedule it a second time (and must not
+ * clean up synchronously, as we are called from the child-death
+ * notification).
+ *
+ * @param[in,out] tc context to fail
+ * @param ec error code to return to the client
+ * @param hint hint text to return to the client
+ */
+static void
+stage_fail (struct TALER_MHD_TypstContext *tc,
+ enum TALER_ErrorCode ec,
+ const char *hint)
+{
+ typst_context_fail (tc,
+ ec,
+ hint);
+ if (NULL == tc->t)
+ tc->t = GNUNET_SCHEDULER_add_now (&cancel_async,
+ tc);
+}
+
+
+/**
* Called when a typst helper exited.
*
* @param cls our `struct TypstStage *`
@@ -484,10 +517,16 @@ typst_done_cb (void *cls,
case GNUNET_OS_PROCESS_RUNNING:
/* we should not get this notification */
GNUNET_break (0);
+ stage_fail (tc,
+ TALER_EC_EXCHANGE_GENERIC_TYPST_CRASH,
+ "Typst in unexpected state");
return;
case GNUNET_OS_PROCESS_STOPPED:
/* Someone is SIGSTOPing our helper!? */
GNUNET_break (0);
+ stage_fail (tc,
+ TALER_EC_EXCHANGE_GENERIC_TYPST_CRASH,
+ "Typst was stopped");
return;
case GNUNET_OS_PROCESS_EXITED:
if (0 != exit_code)
@@ -501,12 +540,9 @@ typst_done_cb (void *cls,
sizeof (err),
"Typst exited with status %d",
(int) exit_code);
- typst_context_fail (tc,
- TALER_EC_EXCHANGE_GENERIC_TYPST_TEMPLATE_FAILURE,
- err);
- GNUNET_assert (NULL == tc->t);
- tc->t = GNUNET_SCHEDULER_add_now (&cancel_async,
- tc);
+ stage_fail (tc,
+ TALER_EC_EXCHANGE_GENERIC_TYPST_TEMPLATE_FAILURE,
+ err);
return;
}
break;
@@ -521,12 +557,9 @@ typst_done_cb (void *cls,
sizeof (err),
"Typst died with signal %d",
(int) exit_code);
- typst_context_fail (tc,
- TALER_EC_EXCHANGE_GENERIC_TYPST_CRASH,
- err);
- GNUNET_assert (NULL == tc->t);
- tc->t = GNUNET_SCHEDULER_add_now (&cancel_async,
- tc);
+ stage_fail (tc,
+ TALER_EC_EXCHANGE_GENERIC_TYPST_CRASH,
+ err);
return;
}
break;
@@ -539,7 +572,8 @@ typst_done_cb (void *cls,
}
if (0 != tc->active_stages)
return;
- GNUNET_assert (NULL == tc->t);
+ if (NULL != tc->t)
+ return; /* clean-up of a failed stage is already scheduled */
tc->t = GNUNET_SCHEDULER_add_now (&complete_response,
tc);
}