fix: proxy ERROR loop, BBR test backpressure, O(1) u_free, test ordering

- tcp_proxy: ERROR silently dropped (no ERROR->ERROR loop), Russian removed from logs
- etcp_bbr: swap min(lo) and max(4*mss) in bbr_bound_cwnd_for_inflight_model
- test_etcp_bbr: fix cwnd comparison (packets vs bytes)
- ll_queue: double-put detection (abort), Floyd cycle detection in consistency check
- ll_queue: QUEUE_DEBUG commented out (was always-on, O(N) per put)
- mem: u_free_impl now O(1) via doubly-linked list, double-free detection
- bbr_integration: queue_waiter_wait + call_soon backpressure (threshold=1)
- tests/Makefile.am: fast tests first, *.log cleanup before run
This commit is contained in:
Evgeny committed 2026-06-03 02:06:09 +03:00
1 parent 7f5325ac24
commit 331d43c6f7
10 files changed
+128 -77

No files matched your search

+39 -3
View File
@@ -309,6 +309,12 @@ int queue_data_put(struct ll_queue* q, struct ll_entry* entry) {
queue_check_thread(q);
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put detected! entry=%p prev=%p next=%p len=%u",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next, entry->len);
abort();
}
if (q->hash_size > 0) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] Put no-hash data to hash queue",q->name);
queue_dgram_free(entry);
@@ -350,6 +356,12 @@ int queue_data_put_with_index(struct ll_queue* q, struct ll_entry* entry) {
queue_check_thread(q);
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put_with_index detected! entry=%p prev=%p next=%p",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next);
abort();
}
if (q->index_size == 0 || (size_t)q->index_offset + q->index_size > (size_t)entry->size) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] invalid index: offset=%u size=%u (data_size=%u)",q->name, q->index_offset, q->index_size, entry->size);
queue_dgram_free(entry);
@@ -393,6 +405,12 @@ int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry) {
queue_check_thread(q);
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put_first detected! entry=%p prev=%p next=%p",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next);
abort();
}
if (q->hash_size > 0) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] Put no-hash data to hash queue",q->name);
queue_dgram_free(entry);
@@ -426,6 +444,12 @@ int queue_data_put_first_with_index(struct ll_queue* q, struct ll_entry* entry)
queue_check_thread(q);
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put_first_with_index detected! entry=%p prev=%p next=%p",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next);
abort();
}
if (q->index_size == 0 || (size_t)q->index_offset + q->index_size > (size_t)entry->size) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] invalid index: offset=%u size=%u (data_size=%u)",q->name, q->index_offset, q->index_size, entry->size);
queue_dgram_free(entry);
@@ -505,14 +529,27 @@ int queue_entry_count(struct ll_queue* q) {
// Функция проверки консистентности count и total_bytes
// Возвращает 0 если ok, -1 если есть несоответствия
int queue_check_consistency(struct ll_queue* q) {
if (!q) return -1; // Недопустимая очередь
if (!q) return -1;
// Проверка: если count > 0, то head не должен быть NULL
if (q->count > 0 && !q->head) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count=%d but head is NULL!",
q->name ? q->name : "unknown", q->count);
return -1;
}
// Floyd cycle detection — за O(N) без риска зависания
{
struct ll_entry *slow = q->head, *fast = q->head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': CYCLE detected! entry=%p count=%d",
q->name ? q->name : "unknown", (void*)slow, q->count);
abort();
}
}
}
int actual_count = 0;
size_t actual_bytes = 0;
@@ -523,7 +560,6 @@ int queue_check_consistency(struct ll_queue* q) {
actual_bytes += current->int_len;
if (current->next) {
if (current->next->prev != current) {
// Несоответствие в связях prev/next
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': prev/next error at entry %p != %p entries: %d!=%d bytes: %zu!=%zu",
q->name ? q->name : "unknown", (void*)current, (void*)current->next->prev, actual_count, q->count, actual_bytes, q->total_bytes);
return -1;
+1 -1
View File
@@ -12,7 +12,7 @@
#include <pthread.h>
#endif
#define QUEUE_DEBUG 1
//#define QUEUE_DEBUG 1 // раскомментировать для отладки очереди
//#define QUEUE_THREAD_CHECK 1 // 0 to disable
/**
+24 -39
View File
@@ -14,8 +14,9 @@
#define PADDING_FILL 0xAA
#define METADATA_SIZE 128
#define POINTER_SIZE sizeof(void*)
#define LOCATION_MAX (METADATA_SIZE - POINTER_SIZE)
#define NEXT_OFFSET LOCATION_MAX
#define LOCATION_MAX (METADATA_SIZE - POINTER_SIZE * 2)
#define PREV_OFFSET LOCATION_MAX
#define NEXT_OFFSET (LOCATION_MAX + POINTER_SIZE)
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
#include <execinfo.h>
@@ -136,8 +137,12 @@ void* u_malloc_impl(uint32_t size, const char* location) {
*(uint32_t*)(prefix_start + BOUNDARY_CHECK_SIZE + 8 + size) = CANARY;
// Add to list (thread-safe)
LOCK();
void** prev_ptr = (void**)(base + PREV_OFFSET);
void** next_ptr = (void**)(base + NEXT_OFFSET);
*prev_ptr = NULL;
*next_ptr = allocated_head;
if (allocated_head)
*(void**)((uint8_t*)allocated_head + PREV_OFFSET) = base;
allocated_head = base;
allocated_count++;
allocations_count++;
@@ -175,29 +180,14 @@ void u_free_impl(void* ptr, const char* location) {
uint8_t* base = (uint8_t*)ptr - 8 - BOUNDARY_CHECK_SIZE - METADATA_SIZE;
char* alloc_loc = (char*)base;
uint32_t size = *(uint32_t*)(base + METADATA_SIZE + BOUNDARY_CHECK_SIZE + 4);
// Remove from linked list (thread-safe)
// Remove from doubly-linked list (O(1))
LOCK();
void* prev = NULL;
void* curr = allocated_head;
bool found = false;
while (curr) {
if (curr == base) {
if (prev) {
*(void**)((uint8_t*)prev + NEXT_OFFSET) = *(void**)((uint8_t*)curr + NEXT_OFFSET);
} else {
allocated_head = *(void**)((uint8_t*)curr + NEXT_OFFSET);
}
allocated_count--;
frees_count++;
found = true;
break;
}
prev = curr;
curr = *(void**)((uint8_t*)curr + NEXT_OFFSET);
}
void* prev = *(void**)(base + PREV_OFFSET);
void* next = *(void**)(base + NEXT_OFFSET);
size_t active_count = allocated_count;
UNLOCK();
if (!found) {
if (prev == NULL && allocated_head != base) {
UNLOCK();
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "========================================");
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "DOUBLE FREE DETECTED");
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "========================================");
@@ -215,24 +205,19 @@ void u_free_impl(void* ptr, const char* location) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "--- User data dump at %p (%u of %u bytes) ---", ptr, dump_size, size);
hex_dump(ptr, dump_size);
}
#if BACKTRACE_ENABLED
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "--- Backtrace ---");
# if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
void* bt_buf[32];
int bt_size = backtrace(bt_buf, 32);
char** bt_symbols = backtrace_symbols(bt_buf, bt_size);
if (bt_symbols) {
for (int i = 0; i < bt_size; i++) DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " #%d %s", i, bt_symbols[i]);
free(bt_symbols);
}
# elif defined(_WIN32)
void* bt_buf[32];
USHORT frames = CaptureStackBackTrace(0, 32, bt_buf, NULL);
for (USHORT i = 0; i < frames; i++) DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " #%d %p", i, bt_buf[i]);
# endif
#endif
exit(EXIT_FAILURE);
}
if (prev)
*(void**)((uint8_t*)prev + NEXT_OFFSET) = next;
else
allocated_head = next;
if (next)
*(void**)((uint8_t*)next + PREV_OFFSET) = prev;
allocated_count--;
frees_count++;
UNLOCK();
uint32_t total = size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE;
memset(base, 0, total);
free(base);