From bb87a0845b68dac3326d3275e4824af2f82a6e54 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 21 Oct 2026 19:03:39 +0200 Subject: [PATCH] Verify config updates preserve files and allocations under OOM --- tests/Makefile.am | 3 ++- tests/test_config_updater.c | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 3ae3ec36..9983d614 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -301,7 +301,8 @@ test_mem_LDFLAGS = -Wl,--wrap=malloc test_config_updater_SOURCES = test_config_updater.c test_config_updater_LDADD = $(LIBUTUN) $(COMMON_LIBS) test_config_updater_LDFLAGS = -Wl,--wrap=fopen -Wl,--wrap=fdopen -Wl,--wrap=fread -Wl,--wrap=ferror \ - -Wl,--wrap=fwrite -Wl,--wrap=fflush -Wl,--wrap=fclose -Wl,--wrap=fsync -Wl,--wrap=fchmod -Wl,--wrap=rename -Wl,--wrap=open + -Wl,--wrap=fwrite -Wl,--wrap=fflush -Wl,--wrap=fclose -Wl,--wrap=fsync -Wl,--wrap=fchmod -Wl,--wrap=rename -Wl,--wrap=open \ + -Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl -Wl,--wrap=u_realloc_impl -Wl,--wrap=u_strdup_impl async_regression_sources = async_regression.c async_regression.h async_regression_ldflags = -Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl -Wl,--wrap=u_realloc_impl \ diff --git a/tests/test_config_updater.c b/tests/test_config_updater.c index da2cabfd..402799b5 100644 --- a/tests/test_config_updater.c +++ b/tests/test_config_updater.c @@ -5,6 +5,7 @@ #include "../src/transport_layer/secure_channel.h" #include "../lib/platform_compat.h" #include "../lib/debug_config.h" +#include "../lib/mem.h" #include #include #include @@ -18,6 +19,7 @@ enum fault { NONE, READ_OPEN, READ_DATA, READ_CLOSE, TEMP_OPEN, WRITE_DATA, FLUS static enum fault fault; static int injected; static FILE *input_stream, *output_stream; +static int allocation_fail_at, allocation_attempts; static char directory[128], path[256]; static const char *private_hex = "abababababababababababababababababababababababababababababababab"; @@ -32,6 +34,32 @@ extern int __real_fsync(int); extern int __real_fchmod(int, mode_t); extern int __real_rename(const char *, const char *); extern int __real_open(const char *, int, ...); +extern void *__real_u_malloc_impl(uint32_t, const char *); +extern void *__real_u_calloc_impl(uint32_t, uint32_t, const char *); +extern void *__real_u_realloc_impl(void *, uint32_t, const char *); +extern char *__real_u_strdup_impl(const char *, const char *); + +static int allocation_fault(void) { + if (!allocation_fail_at || ++allocation_attempts != allocation_fail_at) return 0; + errno = ENOMEM; + return 1; +} + +void *__wrap_u_malloc_impl(uint32_t size, const char *where) { + return allocation_fault() ? NULL : __real_u_malloc_impl(size, where); +} + +void *__wrap_u_calloc_impl(uint32_t count, uint32_t size, const char *where) { + return allocation_fault() ? NULL : __real_u_calloc_impl(count, size, where); +} + +void *__wrap_u_realloc_impl(void *ptr, uint32_t size, const char *where) { + return allocation_fault() ? NULL : __real_u_realloc_impl(ptr, size, where); +} + +char *__wrap_u_strdup_impl(const char *text, const char *where) { + return allocation_fault() ? NULL : __real_u_strdup_impl(text, where); +} static int inject(enum fault wanted) { if (fault != wanted || injected) return 0; @@ -291,6 +319,27 @@ static void test_failures(void) { DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "PASS links: rejected updates preserve names and original bytes"); } +/* Каждая аллокация на пути обновления может отказать: исходный файл и баланс памяти сохраняются. */ +static void test_allocation_failures(void) { + const char *original = "[global]\n# sentinel\n"; + size_t baseline = u_get_allocated_count(); + int completed = 0; + for (int index = 1; index < 64; index++) { + write_text(original); + allocation_attempts = 0; allocation_fail_at = index; + int result = config_ensure_keys_and_node_id(path); + allocation_fail_at = 0; + assert(u_get_allocated_count() == baseline); + check_no_temporary(); + if (allocation_attempts < index) { assert(result == 0); completed = 1; break; } + assert(result == -1); + char text[8192]; read_text(text, sizeof(text)); + assert(!strcmp(text, original)); + } + assert(completed); + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "PASS allocation failures: every allocation, original bytes and resource balance"); +} + int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); @@ -301,6 +350,7 @@ int main(void) { test_identity_and_text(); test_reality_and_validation(); test_failures(); + test_allocation_failures(); assert(!unlink(path) && !rmdir(directory)); DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "PASS config updater regression suite"); return 0;