From 59498e32564931ed260c287125cc9a7d9062069f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=E2=80=99Aquino?= Date: Tue, 17 Feb 2026 04:55:07 -0800 Subject: [PATCH] Fix double-free crash when creating empty NdbFilter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When ndb_filter_end processes an empty filter (no fields added), it calls realloc(filter->elem_buf.start, 0) which frees the memory and returns NULL. The existing code only updated the pointer if realloc returned non-NULL, leaving elem_buf.start pointing to freed memory. This caused a double-free crash when ndb_filter_destroy later called free() on the dangling pointer. Fix by explicitly setting filter->elem_buf.start to NULL when realloc returns NULL due to zero-size allocation, and update the assertion to allow NULL pointers for empty filters. ndb_filter_destroy already checks for NULL before freeing. Closes: https://github.com/damus-io/damus/issues/3634 Changelog-Fixed: Fix memory corruption crash when creating empty filters Signed-off-by: Daniel D’Aquino --- nostrdb/src/nostrdb.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/nostrdb/src/nostrdb.c b/nostrdb/src/nostrdb.c index ecf84a55..a06e5821 100644 --- a/nostrdb/src/nostrdb.c +++ b/nostrdb/src/nostrdb.c @@ -614,10 +614,20 @@ int ndb_filter_end(struct ndb_filter *filter) memmove(filter->elem_buf.p, filter->data_buf.start, data_len); // realloc the whole thing - rel = realloc(filter->elem_buf.start, elem_len + data_len); - if (rel) - filter->elem_buf.start = rel; - assert(filter->elem_buf.start); + size_t new_size = elem_len + data_len; + if (new_size == 0) { + // Avoid calling realloc with size 0 (implementation-defined behavior) + // Explicitly free and set to NULL + free(filter->elem_buf.start); + filter->elem_buf.start = NULL; + } else { + rel = realloc(filter->elem_buf.start, new_size); + if (rel) { + filter->elem_buf.start = rel; + } + // Assert allocation succeeded for non-zero size + assert(filter->elem_buf.start); + } filter->elem_buf.end = filter->elem_buf.start + elem_len; filter->elem_buf.p = filter->elem_buf.end;