Fix allocation size overflow, zero-size OOM and debug category parsing
This commit is contained in:
1 parent
00819654cf
commit
7e39f16e0f
6 files changed
+217
-73
No files matched your search
+11
-18
@@ -460,7 +460,7 @@ void debug_set_log_hook(debug_log_hook_fn hook) {
|
||||
g_log_hook = hook;
|
||||
}
|
||||
|
||||
/* Parse debug configuration from string (e.g., "ll_queue:debug,uasync:info,memory:warn,etcp:error") */
|
||||
/* Настройка отдельных категорий: "sys=debug,etcp=error"; разделитель ':' также допустим. */
|
||||
int debug_parse_config(const char* config_string) {
|
||||
if (!config_string || !*config_string) {
|
||||
return 0;
|
||||
@@ -468,12 +468,10 @@ int debug_parse_config(const char* config_string) {
|
||||
|
||||
char* str = u_strdup(config_string);
|
||||
if (!str) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to allocate debug configuration copy");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_category_t categories = 0;
|
||||
debug_level_t level = DEBUG_LEVEL_NONE;
|
||||
|
||||
char* token = strtok(str, ",");
|
||||
while (token) {
|
||||
/* Trim leading spaces */
|
||||
@@ -481,15 +479,16 @@ int debug_parse_config(const char* config_string) {
|
||||
token++;
|
||||
}
|
||||
|
||||
char* colon = strchr(token, ':');
|
||||
if (!colon) {
|
||||
char* separator = strpbrk(token, "=:");
|
||||
if (!separator) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Missing '=' or ':' in debug setting '%s'", token);
|
||||
u_free(str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*colon = '\0';
|
||||
*separator = '\0';
|
||||
char* category_name = token;
|
||||
char* level_name = colon + 1;
|
||||
char* level_name = separator + 1;
|
||||
|
||||
/* Trim leading spaces in level_name */
|
||||
while (isspace(*level_name)) {
|
||||
@@ -497,22 +496,16 @@ int debug_parse_config(const char* config_string) {
|
||||
}
|
||||
|
||||
debug_category_t cat = get_category_by_name(category_name);
|
||||
if (cat == DEBUG_CATEGORY_NONE) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Unknown debug category '%s'", category_name);
|
||||
if (cat <= DEBUG_CATEGORY_NONE || cat >= DEBUG_CATEGORY_COUNT) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Unknown or unsupported debug category '%s' (expected an individual category)", category_name);
|
||||
u_free(str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_level_t lev = debug_level_from_name(level_name);
|
||||
|
||||
/* Set per-category level */
|
||||
int idx = 0;
|
||||
while (!(cat & (1ULL << idx)) && idx < DEBUG_CATEGORY_COUNT) {
|
||||
idx++;
|
||||
}
|
||||
if (idx < DEBUG_CATEGORY_COUNT) {
|
||||
g_debug_config.category_levels[idx] = lev;
|
||||
}
|
||||
debug_set_category_level(cat, lev);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Applied debug setting: %s=%s (category=%d, level=%d)", category_name, level_name, cat, lev);
|
||||
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
+3
-1
@@ -173,7 +173,9 @@ void debug_output(debug_level_t level, debug_category_t category_idx,
|
||||
typedef void (*debug_log_hook_fn)(int level, const char* category, const char* message);
|
||||
void debug_set_log_hook(debug_log_hook_fn hook);
|
||||
|
||||
/* Parse debug configuration from string (e.g. "etcp=trace,config=info") */
|
||||
/* Настройка отдельных категорий: "etcp=trace,config=info" (также ':' вместо '=').
|
||||
* NULL/пустая строка ничего не меняет. Возвращает 0 при успехе, -1 при ошибке;
|
||||
* настройки до ошибочного элемента остаются применёнными. */
|
||||
int debug_parse_config(const char* config_string);
|
||||
|
||||
/* Convenience macros for debug output */
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define CANARY 0xDEADBEEF
|
||||
#define PADDING_FILL 0xAA
|
||||
#define METADATA_SIZE 128
|
||||
#define ALLOCATION_OVERHEAD (12 + (size_t)2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE)
|
||||
#define POINTER_SIZE sizeof(void*)
|
||||
#define LOCATION_MAX (METADATA_SIZE - POINTER_SIZE * 2)
|
||||
#define PREV_OFFSET LOCATION_MAX
|
||||
@@ -89,7 +90,7 @@ void u_check(void* ptr, const char* text, const char* location) {
|
||||
uint8_t* prefix_start = base + METADATA_SIZE;
|
||||
uint32_t* pre_canary = (uint32_t*)(prefix_start + BOUNDARY_CHECK_SIZE);
|
||||
uint32_t size = *(uint32_t*)(prefix_start + BOUNDARY_CHECK_SIZE + 4);
|
||||
uint32_t total = size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE;
|
||||
size_t total = (size_t)size + ALLOCATION_OVERHEAD;
|
||||
uint8_t* user = (uint8_t*)ptr;
|
||||
bool error = false;
|
||||
for (size_t i = 0; i < BOUNDARY_CHECK_SIZE; i++) {
|
||||
@@ -117,7 +118,7 @@ void u_check(void* ptr, const char* text, const char* location) {
|
||||
}
|
||||
if (error) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Allocated at: %s", location, text, alloc_loc);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Memory block size (user): %u bytes, total allocated: %u bytes", location, text, size, total);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Memory block size (user): %u bytes, total allocated: %zu bytes", location, text, size, total);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Full memory dump at base %p:", location, text, base);
|
||||
hex_dump(base, total);
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -125,13 +126,21 @@ void u_check(void* ptr, const char* text, const char* location) {
|
||||
}
|
||||
|
||||
void* u_malloc_impl(uint32_t size, const char* location) {
|
||||
size_t total = size;
|
||||
if (total > SIZE_MAX - ALLOCATION_OVERHEAD) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "MALLOC OVERFLOW: %u user bytes + %zu overhead bytes at %s", size, ALLOCATION_OVERHEAD, location);
|
||||
return NULL;
|
||||
}
|
||||
if (size >= LARGE_ALLOC_LOG_THRESHOLD) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_SYS, "LARGE ALLOC: %u bytes (%.1f MB) at %s",
|
||||
size, (double)size / (1024.0 * 1024.0), location);
|
||||
}
|
||||
uint32_t total = size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE;
|
||||
total += ALLOCATION_OVERHEAD;
|
||||
uint8_t* base = (uint8_t*)malloc(total);
|
||||
if (!base && size > 0) return NULL;
|
||||
if (!base) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "MALLOC FAILED: %u user bytes, %zu total bytes at %s", size, total, location);
|
||||
return NULL;
|
||||
}
|
||||
memset(base, PADDING_FILL, total);
|
||||
// Set metadata
|
||||
size_t loc_len = strlen(location);
|
||||
@@ -209,7 +218,7 @@ void u_free_impl(void* ptr, const char* location) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Base: %p", (void*)base);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Allocated at: %s", alloc_loc);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "User size: %u bytes", size);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Total allocated: %u bytes", size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Total allocated: %zu bytes", (size_t)size + ALLOCATION_OVERHEAD);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Active allocs: %zu", active_count);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "--- Metadata dump at %p (%u bytes) ---", (void*)base, (unsigned)(METADATA_SIZE + BOUNDARY_CHECK_SIZE + 8));
|
||||
hex_dump(base, METADATA_SIZE + BOUNDARY_CHECK_SIZE + 8);
|
||||
@@ -231,7 +240,7 @@ void u_free_impl(void* ptr, const char* location) {
|
||||
allocated_count--;
|
||||
frees_count++;
|
||||
UNLOCK();
|
||||
uint32_t total = size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE;
|
||||
size_t total = (size_t)size + ALLOCATION_OVERHEAD;
|
||||
memset(base, 0, total);
|
||||
free(base);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ check_PROGRAMS = \
|
||||
|
||||
if OS_LINUX
|
||||
check_PROGRAMS += \
|
||||
test_mem \
|
||||
test_stun_nat \
|
||||
test_reality_fallback \
|
||||
test_etcp_padding \
|
||||
@@ -290,6 +291,10 @@ test_pool_corruption_log_SOURCES = test_pool_corruption_log.c
|
||||
test_pool_corruption_log_LDADD = $(COMMON_LIBS)
|
||||
|
||||
# Linux/ELF: faults внедряются линкером, тестовых веток в библиотеках нет.
|
||||
test_mem_SOURCES = test_mem.c
|
||||
test_mem_LDADD = $(COMMON_LIBS)
|
||||
test_mem_LDFLAGS = -Wl,--wrap=malloc
|
||||
|
||||
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 \
|
||||
-Wl,--wrap=gettimeofday -Wl,--wrap=epoll_wait -Wl,--wrap=epoll_ctl -Wl,--wrap=eventfd -Wl,--wrap=epoll_create1
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/* Проверяем размеры реальных malloc и OOM без выделения гигабайт памяти. */
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug_config.h"
|
||||
#include "mem.h"
|
||||
|
||||
#define CHECK(expr) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #expr); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool fail_malloc;
|
||||
static size_t malloc_calls;
|
||||
static size_t malloc_size;
|
||||
|
||||
void* __real_malloc(size_t size);
|
||||
|
||||
void* __wrap_malloc(size_t size) {
|
||||
malloc_calls++;
|
||||
malloc_size = size;
|
||||
if (fail_malloc) {
|
||||
fail_malloc = false;
|
||||
return NULL;
|
||||
}
|
||||
return __real_malloc(size);
|
||||
}
|
||||
|
||||
static void test_small_allocations(void) {
|
||||
const uint32_t sizes[] = {0, 1, 3, 4, 255, 256, 257, 1024};
|
||||
size_t count = u_get_allocated_count();
|
||||
for (size_t i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) {
|
||||
uint8_t* ptr = u_malloc(sizes[i]);
|
||||
CHECK(ptr != NULL);
|
||||
CHECK(u_get_allocated_count() == count + 1);
|
||||
memset(ptr, 0x5a, sizes[i]);
|
||||
u_check(ptr, "small allocation", LOCATION);
|
||||
u_free(ptr);
|
||||
CHECK(u_get_allocated_count() == count);
|
||||
}
|
||||
puts("PASS: zero, odd and ordinary allocation sizes");
|
||||
}
|
||||
|
||||
static void test_oom(void) {
|
||||
size_t count = u_get_allocated_count();
|
||||
fail_malloc = true;
|
||||
CHECK(u_malloc(0) == NULL);
|
||||
CHECK(!fail_malloc);
|
||||
fail_malloc = true;
|
||||
CHECK(u_calloc(0, UINT32_MAX) == NULL);
|
||||
CHECK(!fail_malloc);
|
||||
fail_malloc = true;
|
||||
CHECK(u_calloc(UINT32_MAX, 0) == NULL);
|
||||
CHECK(!fail_malloc);
|
||||
fail_malloc = true;
|
||||
CHECK(u_realloc(NULL, 0) == NULL);
|
||||
CHECK(!fail_malloc);
|
||||
fail_malloc = true;
|
||||
CHECK(u_malloc(17) == NULL);
|
||||
CHECK(!fail_malloc);
|
||||
CHECK(u_get_allocated_count() == count);
|
||||
|
||||
char* ptr = u_strdup("preserve on OOM");
|
||||
CHECK(ptr != NULL);
|
||||
fail_malloc = true;
|
||||
CHECK(u_realloc(ptr, 128) == NULL);
|
||||
CHECK(!fail_malloc);
|
||||
CHECK(strcmp(ptr, "preserve on OOM") == 0);
|
||||
CHECK(u_get_allocated_count() == count + 1);
|
||||
u_free(ptr);
|
||||
CHECK(u_get_allocated_count() == count);
|
||||
puts("PASS: OOM for zero/nonzero sizes and realloc preserves its old block");
|
||||
}
|
||||
|
||||
static void test_large_sizes(void) {
|
||||
/* Измеряем служебный размер по запросу malloc для пустого блока. */
|
||||
void* empty = u_malloc(0);
|
||||
CHECK(empty != NULL);
|
||||
size_t overhead = malloc_size;
|
||||
u_free(empty);
|
||||
CHECK(overhead > 0 && overhead <= 1024);
|
||||
const uint32_t sizes[] = {
|
||||
UINT32_MAX - 1024, UINT32_MAX - (uint32_t)overhead, UINT32_MAX - (uint32_t)overhead + 1, UINT32_MAX - 1, UINT32_MAX
|
||||
};
|
||||
size_t count = u_get_allocated_count();
|
||||
char* old = u_strdup("preserve on large OOM");
|
||||
CHECK(old != NULL);
|
||||
for (size_t i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) {
|
||||
for (int api = 0; api < 3; api++) {
|
||||
size_t calls = malloc_calls;
|
||||
fail_malloc = true;
|
||||
void* ptr;
|
||||
if (api == 0) ptr = u_malloc(sizes[i]);
|
||||
else if (api == 1) ptr = u_calloc(sizes[i], 1);
|
||||
else ptr = u_realloc(old, sizes[i]);
|
||||
CHECK(ptr == NULL);
|
||||
if ((uint64_t)sizes[i] + overhead > SIZE_MAX) {
|
||||
CHECK(malloc_calls == calls);
|
||||
CHECK(fail_malloc);
|
||||
fail_malloc = false;
|
||||
} else {
|
||||
CHECK(malloc_calls == calls + 1);
|
||||
CHECK(!fail_malloc);
|
||||
CHECK(malloc_size == (uint64_t)sizes[i] + overhead);
|
||||
}
|
||||
CHECK(u_get_allocated_count() == count + 1);
|
||||
CHECK(strcmp(old, "preserve on large OOM") == 0);
|
||||
}
|
||||
}
|
||||
u_free(old);
|
||||
CHECK(u_get_allocated_count() == count);
|
||||
puts("PASS: sizes near UINT32_MAX reach malloc intact or are rejected before overflow");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init();
|
||||
debug_set_level(DEBUG_LEVEL_ERROR);
|
||||
debug_set_category_level(DEBUG_CATEGORY_SYS, DEBUG_LEVEL_WARN);
|
||||
test_small_allocations();
|
||||
test_oom();
|
||||
test_large_sizes();
|
||||
CHECK(u_get_allocated_count() == 0);
|
||||
puts("PASS: mem regression tests");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
/**
|
||||
* Test for memory pool optimization and configuration file support
|
||||
* Проверка пулов памяти и настройки категорий отладки из строки.
|
||||
*/
|
||||
|
||||
#include "test_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "../lib/memory_pool.h"
|
||||
@@ -22,12 +20,60 @@ static void test_waiter_callback(struct ll_queue* q, void* arg) {
|
||||
test_callback_count++;
|
||||
}
|
||||
|
||||
static int test_debug_config(void) {
|
||||
const char* configs[] = {
|
||||
"sys=debug,etcp=error,crypto=disabled,discovery=trace",
|
||||
"sys:debug,etcp:error,crypto:disabled,discovery:trace"
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); i++) {
|
||||
debug_config_init();
|
||||
debug_set_level(DEBUG_LEVEL_WARN);
|
||||
if (debug_parse_config(configs[i]) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to parse configuration '%s'", configs[i]);
|
||||
return 1;
|
||||
}
|
||||
for (int category = 0; category < DEBUG_CATEGORY_COUNT; category++) {
|
||||
debug_level_t expected = DEBUG_LEVEL_NONE;
|
||||
if (category == DEBUG_CATEGORY_SYS) expected = DEBUG_LEVEL_DEBUG;
|
||||
else if (category == DEBUG_CATEGORY_ETCP) expected = DEBUG_LEVEL_ERROR;
|
||||
else if (category == DEBUG_CATEGORY_CRYPTO) expected = DEBUG_LEVEL_DISABLED;
|
||||
else if (category == DEBUG_CATEGORY_DISCOVERY) expected = DEBUG_LEVEL_TRACE;
|
||||
if (g_debug_config.category_levels[category] != expected) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Category %d: expected level=%d, got=%d for '%s'",
|
||||
category, expected, g_debug_config.category_levels[category], configs[i]);
|
||||
return 1;
|
||||
}
|
||||
debug_level_t effective = expected == DEBUG_LEVEL_NONE ? DEBUG_LEVEL_WARN : expected;
|
||||
for (debug_level_t level = DEBUG_LEVEL_ERROR; level <= DEBUG_LEVEL_TRACE; level++) {
|
||||
int enabled = effective != DEBUG_LEVEL_DISABLED && level <= effective;
|
||||
if (debug_should_output(level, category) != enabled) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Category %d, level=%d: expected output=%d for '%s'",
|
||||
category, level, enabled, configs[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Configuration '%s': category indices and output filters PASS", configs[i]);
|
||||
}
|
||||
const char* invalid[] = {"sys", "unknown=debug", "all=debug"};
|
||||
for (size_t i = 0; i < sizeof(invalid) / sizeof(invalid[0]); i++) {
|
||||
debug_level_t previous[DEBUG_CATEGORY_COUNT];
|
||||
memcpy(previous, g_debug_config.category_levels, sizeof(previous));
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Expecting rejection of invalid configuration '%s'", invalid[i]);
|
||||
if (debug_parse_config(invalid[i]) != -1 || memcmp(previous, g_debug_config.category_levels, sizeof(previous)) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid configuration '%s' was accepted or changed category levels", invalid[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Invalid debug configurations rejected: PASS");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
debug_config_init();
|
||||
debug_set_level(DEBUG_LEVEL_TRACE);
|
||||
debug_set_categories(DEBUG_CATEGORY_ALL);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Memory Pool and Config File Test ===");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Memory Pool and Debug Configuration Test ===");
|
||||
/* Любой размер блока, включая невыровненный хвост, допустим для malloc/realloc/free. */
|
||||
for (uint32_t size = 1; size <= 17; size++) {
|
||||
unsigned char* p = u_malloc(size);
|
||||
@@ -97,49 +143,8 @@ int main() {
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Memory pool test: PASS");
|
||||
|
||||
// Test 2: Configuration file support
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Test 2: Configuration file support...");
|
||||
|
||||
// Create a test configuration file
|
||||
const char* config_file = "/tmp/debug_test.conf";
|
||||
FILE* f = fopen(config_file, "w");
|
||||
if (f) {
|
||||
fprintf(f, "# Test debug configuration file\n");
|
||||
fprintf(f, "ll_queue:debug\n");
|
||||
fprintf(f, "uasync:info\n");
|
||||
fprintf(f, "memory:warn\n");
|
||||
fprintf(f, "# This is a comment\n");
|
||||
fprintf(f, "etcp:error\n");
|
||||
fclose(f);
|
||||
|
||||
// Parse the configuration string (we don't have file parsing, so use string parsing)
|
||||
const char* config_string = "ll_queue:debug,uasync:info,memory:warn,etcp:error";
|
||||
if (debug_parse_config(config_string) == 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Configuration parsed successfully");
|
||||
|
||||
// Test that configuration was applied
|
||||
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_SYS)) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "LL_QUEUE debug level correctly set");
|
||||
}
|
||||
if (debug_should_output(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_SYS)) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "UASYNC info level correctly set");
|
||||
}
|
||||
if (!debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_ETCP)) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "ETCP correctly limited to error level");
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Note: Hot reload functionality not implemented in current debug system");
|
||||
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to parse configuration");
|
||||
}
|
||||
|
||||
test_unlink(config_file);
|
||||
} else {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to create test configuration file");
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Configuration file test: PASS");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Test 2: Debug configuration strings...");
|
||||
if (test_debug_config() != 0) return 1;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== All tests completed successfully ===");
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user