From 494b8c0b371a4391d93634748acd0667e7a20be8 Mon Sep 17 00:00:00 2001 From: Nick Anderson Date: Thu, 4 Jun 2026 14:26:19 -0500 Subject: [PATCH 1/2] Fix memory leak of existing_info in EvalContextHeapPersistentSave existing_info was allocated via xcalloc but never freed on the early-return (preserve) path, the early-return (read error) path, or the normal fall-through path. Signed-off-by: Nick Anderson --- libpromises/eval_context.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libpromises/eval_context.c b/libpromises/eval_context.c index 3f74b3bd57..5a5b989f27 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -748,6 +748,7 @@ void EvalContextHeapPersistentSave(EvalContext *ctx, const char *name, unsigned Log(LOG_LEVEL_VERBOSE, "Persistent class '%s' is already in a preserved state -- %jd minutes to go", key, (intmax_t)((existing_info->expires - now) / 60)); CloseDB(dbp); + free(existing_info); free(key); free(new_info); return; @@ -757,10 +758,12 @@ void EvalContextHeapPersistentSave(EvalContext *ctx, const char *name, unsigned { Log(LOG_LEVEL_ERR, "While persisting class '%s', error reading existing value", key); CloseDB(dbp); + free(existing_info); free(key); free(new_info); return; } + free(existing_info); } } From a2790387ae4cd330c494673d188c9717a62baa74 Mon Sep 17 00:00:00 2001 From: Nick Anderson Date: Thu, 4 Jun 2026 14:26:50 -0500 Subject: [PATCH 2/2] Improve persistent class logging in EvalContextHeapPersistentSave Replace the generic "Updating persistent class" verbose message with context-aware messages that distinguish between: - Creating a new persistent class (no prior DB record) - Resetting a timer (existing record, policy=reset) - Updating a preserved class (tags changed or class expired) This makes it easier to diagnose persistent class timer behavior from verbose logs without needing to add custom debugging builds. Ticket: ENT-3868 Changelog: Title --- libpromises/eval_context.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/libpromises/eval_context.c b/libpromises/eval_context.c index 5a5b989f27..76c771388a 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -753,6 +753,18 @@ void EvalContextHeapPersistentSave(EvalContext *ctx, const char *name, unsigned free(new_info); return; } + else if (policy == CONTEXT_STATE_POLICY_RESET) + { + Log(LOG_LEVEL_VERBOSE, + "Resetting persistent class '%s' timer to %u minutes (was %jd minutes remaining)", + key, ttl_minutes, (intmax_t)((existing_info->expires - now) / 60)); + } + else + { + Log(LOG_LEVEL_VERBOSE, + "Updating persistent class '%s' (%u minutes, policy preserve)", + key, ttl_minutes); + } } else { @@ -765,10 +777,15 @@ void EvalContextHeapPersistentSave(EvalContext *ctx, const char *name, unsigned } free(existing_info); } + else + { + Log(LOG_LEVEL_VERBOSE, + "Creating persistent class '%s' (%u minutes, policy %s)", + key, ttl_minutes, + policy == CONTEXT_STATE_POLICY_PRESERVE ? "preserve" : "reset"); + } } - Log(LOG_LEVEL_VERBOSE, "Updating persistent class '%s'", key); - WriteDB(dbp, key, new_info, new_info_size); CloseDB(dbp);