From 07f7555c1de5b8b4c88e844686bb1930c2538f98 Mon Sep 17 00:00:00 2001 From: TapTap Date: Sun, 13 Sep 2026 12:57:33 +0200 Subject: [PATCH] fix(server): skip dry-run per-file outcome bookkeeping receiver_save_file appended to context->outcomes for --remove-source-files without the !dry_run guard the multithreaded pipeline has, so a hostile dry-run client could grow outcomes unbounded (raw, uncharged realloc) and force a per-frame ack. Guard the append on !dry_run. --- src/server/receiver.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/server/receiver.c b/src/server/receiver.c index 2fd803e..6e24e88 100644 --- a/src/server/receiver.c +++ b/src/server/receiver.c @@ -479,8 +479,12 @@ static bool receiver_save_file(File* file, void* context_pointer) { file_destroy(file); return false; } - if (result != FILE_SAVE_ERROR && context->config->remove_source_files && !file->is_dir && - !file->is_special && !file->skip && + /* A dry-run receiver mutates nothing AND records no per-file outcomes: a + hostile dry-run client that streamed data frames anyway must not be able to + grow `outcomes` without bound (receiver_outcomes_append reallocs uncharged) + or force a per-frame ack. */ + if (!context->config->dry_run && result != FILE_SAVE_ERROR && + context->config->remove_source_files && !file->is_dir && !file->is_special && !file->skip && !receiver_outcomes_append(&context->outcomes, (unsigned char)result)) { file_destroy(file); return false;