From ea2f76cd7a2144a633e2f4723a9a5e9776b13b2b Mon Sep 17 00:00:00 2001 From: TapTap Date: Sun, 13 Sep 2026 01:18:54 +0200 Subject: [PATCH] fix(receiver): charge per-entry DirTimeList cost; cap client --skip-compress --- src/client/client_cli.c | 5 +++++ src/shared/file_receive.c | 8 ++++++-- tests/test_file.c | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/client/client_cli.c b/src/client/client_cli.c index 400be1b..6600ec0 100644 --- a/src/client/client_cli.c +++ b/src/client/client_cli.c @@ -517,6 +517,11 @@ static int parse_skip_compress(Config* config, const char* value) { token[--len] = '\0'; if (len == 0) continue; + if (config->skip_compress_count >= MAX_SKIP_COMPRESS_SUFFIXES) { + fprintf(stderr, "--skip-compress supports at most %d suffixes\n", MAX_SKIP_COMPRESS_SUFFIXES); + free(list); + return -1; + } if (config_add_pattern(&config->skip_compress_suffixes, &config->skip_compress_count, token, "--skip-compress") != 0) { free(list); diff --git a/src/shared/file_receive.c b/src/shared/file_receive.c index f21867c..477fa68 100644 --- a/src/shared/file_receive.c +++ b/src/shared/file_receive.c @@ -2274,7 +2274,11 @@ bool dir_time_list_add(DirTimeList* list, const char* wire_path, const FileMetad touching the list, leaving it exactly as it was (the caller fails the transfer, which becomes a clean protocol error). */ size_t path_len = strlen(wire_path); - if (list->count >= MAX_DIR_TIME_ENTRIES || path_len > MAX_DIR_TIME_BYTES - list->bytes) + /* Charge the whole per-entry cost (path copy + pointer slot + metadata + struct), not just the path, so the array growth is bounded by the same + cumulative budget. */ + size_t entry_cost = path_len + sizeof(FileMetadata) + sizeof(char*); + if (list->count >= MAX_DIR_TIME_ENTRIES || entry_cost > MAX_DIR_TIME_BYTES - list->bytes) return false; if (list->count == list->capacity) { size_t new_capacity = list->capacity == 0 ? 16 : list->capacity * 2; @@ -2302,7 +2306,7 @@ bool dir_time_list_add(DirTimeList* list, const char* wire_path, const FileMetad list->paths[list->count] = copy; list->entries[list->count] = *metadata; list->count++; - list->bytes += path_len; + list->bytes += entry_cost; return true; } diff --git a/tests/test_file.c b/tests/test_file.c index 0f0225d..928f544 100644 --- a/tests/test_file.c +++ b/tests/test_file.c @@ -1396,7 +1396,7 @@ static void test_dir_time_list_cap() { EXPECT_TRUE(list.bytes == before_bytes); } else { EXPECT_TRUE(list.count == before_count + 1); - EXPECT_TRUE(list.bytes == before_bytes + path_len); + EXPECT_TRUE(list.bytes == before_bytes + path_len + sizeof(FileMetadata) + sizeof(char*)); } } EXPECT_TRUE(rejected);