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:
1 parent
7f5325ac24
commit
331d43c6f7
10 files changed
+128
-77
No files matched your search
+39
-3
@@ -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
@@ -12,7 +12,7 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#define QUEUE_DEBUG 1
|
||||
//#define QUEUE_DEBUG 1 // раскомментировать для отладки очереди
|
||||
//#define QUEUE_THREAD_CHECK 1 // 0 to disable
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user