Box TLS-SLL + free boundary hardening: normalize C0–C6 to base (ptr-1) at free boundary; route all caches/freelists via base; replace remaining g_tls_sll_head direct writes with Box API (tls_sll_push/splice) in refill/magazine/ultra; keep C7 excluded. Fixes rbp=0xa0 free crash by preventing header overwrite and centralizing TLS-SLL invariants.
This commit is contained in:
164
core/box/tls_sll_box.h
Normal file
164
core/box/tls_sll_box.h
Normal file
@ -0,0 +1,164 @@
|
||||
// tls_sll_box.h - Box TLS-SLL: Single-Linked List API (C7-safe)
|
||||
//
|
||||
// Purpose: Centralized TLS SLL management with C7 protection
|
||||
// Design: Zero-overhead static inline API, C7 always rejected
|
||||
//
|
||||
// Key Rules:
|
||||
// 1. C7 (1KB headerless) is ALWAYS rejected (returns false/0)
|
||||
// 2. All SLL direct writes MUST go through this API
|
||||
// 3. Pop returns with first 8 bytes cleared for C7 (safety)
|
||||
// 4. Capacity checks prevent overflow
|
||||
//
|
||||
// Architecture:
|
||||
// - Box TLS-SLL (this): Push/Pop/Splice authority
|
||||
// - Caller: Provides capacity limits, handles fallback on failure
|
||||
//
|
||||
// Performance:
|
||||
// - Static inline → zero function call overhead
|
||||
// - C7 check: 1 comparison + predict-not-taken (< 1 cycle)
|
||||
// - Same performance as direct SLL access for C0-C6
|
||||
|
||||
#ifndef TLS_SLL_BOX_H
|
||||
#define TLS_SLL_BOX_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h> // For fprintf in debug
|
||||
#include <stdlib.h> // For abort in debug
|
||||
#include "../hakmem_tiny_config.h" // For TINY_NUM_CLASSES
|
||||
|
||||
// External TLS SLL state (defined elsewhere)
|
||||
extern __thread void* g_tls_sll_head[TINY_NUM_CLASSES];
|
||||
extern __thread uint32_t g_tls_sll_count[TINY_NUM_CLASSES];
|
||||
|
||||
// ========== Push ==========
|
||||
|
||||
// Push pointer to TLS SLL
|
||||
// Returns: true on success, false if C7 or capacity exceeded
|
||||
//
|
||||
// Safety:
|
||||
// - C7 always rejected (headerless, first 8 bytes = user data)
|
||||
// - Capacity check prevents overflow
|
||||
// - Caller must handle fallback (e.g., meta->freelist)
|
||||
//
|
||||
// Performance: 2-3 cycles (C0-C6), < 1 cycle (C7 fast rejection)
|
||||
static inline bool tls_sll_push(int class_idx, void* ptr, uint32_t capacity) {
|
||||
// CRITICAL: C7 (1KB) is headerless - MUST NOT use TLS SLL
|
||||
// Reason: SLL stores next pointer in first 8 bytes (user data for C7)
|
||||
if (__builtin_expect(class_idx == 7, 0)) {
|
||||
return false; // C7 rejected
|
||||
}
|
||||
|
||||
// Capacity check
|
||||
if (g_tls_sll_count[class_idx] >= capacity) {
|
||||
return false; // SLL full
|
||||
}
|
||||
|
||||
// Push to SLL (standard linked list push)
|
||||
*(void**)ptr = g_tls_sll_head[class_idx];
|
||||
g_tls_sll_head[class_idx] = ptr;
|
||||
g_tls_sll_count[class_idx]++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== Pop ==========
|
||||
|
||||
// Pop pointer from TLS SLL
|
||||
// Returns: true on success (writes to *out), false if empty
|
||||
//
|
||||
// Safety:
|
||||
// - C7 protection: clears first 8 bytes on pop (prevents next pointer leak)
|
||||
// - NULL check before deref
|
||||
//
|
||||
// Performance: 3-4 cycles
|
||||
static inline bool tls_sll_pop(int class_idx, void** out) {
|
||||
void* head = g_tls_sll_head[class_idx];
|
||||
if (!head) {
|
||||
return false; // SLL empty
|
||||
}
|
||||
|
||||
// Pop from SLL
|
||||
void* next = *(void**)head;
|
||||
g_tls_sll_head[class_idx] = next;
|
||||
if (g_tls_sll_count[class_idx] > 0) {
|
||||
g_tls_sll_count[class_idx]--;
|
||||
}
|
||||
|
||||
// CRITICAL: C7 (1KB) returns with first 8 bytes cleared
|
||||
// Reason: C7 is headerless, first 8 bytes are user data area
|
||||
// Without this: user sees stale SLL next pointer → corruption
|
||||
// Cost: 1 store instruction (~1 cycle), only for C7 (~1% of allocations)
|
||||
//
|
||||
// Note: C0-C6 have 1-byte header, so first 8 bytes are safe (header hides next)
|
||||
if (__builtin_expect(class_idx == 7, 0)) {
|
||||
*(void**)head = NULL;
|
||||
}
|
||||
|
||||
*out = head;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== Splice ==========
|
||||
|
||||
// Splice chain of pointers to TLS SLL (batch push)
|
||||
// Returns: actual count moved (0 for C7 or if capacity exceeded)
|
||||
//
|
||||
// Safety:
|
||||
// - C7 always returns 0 (no splice)
|
||||
// - Capacity check limits splice size
|
||||
// - Chain traversal with safety (breaks on NULL)
|
||||
//
|
||||
// Performance: ~5 cycles + O(count) for chain traversal
|
||||
static inline uint32_t tls_sll_splice(int class_idx, void* chain_head, uint32_t count, uint32_t capacity) {
|
||||
// CRITICAL: C7 (1KB) is headerless - MUST NOT splice to TLS SLL
|
||||
if (__builtin_expect(class_idx == 7, 0)) {
|
||||
return 0; // C7 rejected
|
||||
}
|
||||
|
||||
// Calculate available capacity
|
||||
uint32_t available = (capacity > g_tls_sll_count[class_idx])
|
||||
? (capacity - g_tls_sll_count[class_idx]) : 0;
|
||||
if (available == 0 || count == 0 || !chain_head) {
|
||||
return 0; // No space or empty chain
|
||||
}
|
||||
|
||||
// Limit splice size to available capacity
|
||||
uint32_t to_move = (count < available) ? count : available;
|
||||
|
||||
// Find chain tail (traverse to_move - 1 nodes)
|
||||
void* tail = chain_head;
|
||||
for (uint32_t i = 1; i < to_move; i++) {
|
||||
void* next = *(void**)tail;
|
||||
if (!next) {
|
||||
// Chain shorter than expected, adjust to_move
|
||||
to_move = i;
|
||||
break;
|
||||
}
|
||||
tail = next;
|
||||
}
|
||||
|
||||
// Splice chain to SLL head
|
||||
*(void**)tail = g_tls_sll_head[class_idx];
|
||||
g_tls_sll_head[class_idx] = chain_head;
|
||||
g_tls_sll_count[class_idx] += to_move;
|
||||
|
||||
return to_move;
|
||||
}
|
||||
|
||||
// ========== Debug/Stats (optional) ==========
|
||||
|
||||
#if !HAKMEM_BUILD_RELEASE
|
||||
// Verify C7 is not in SLL (debug only, call at safe points)
|
||||
static inline void tls_sll_verify_no_c7(void) {
|
||||
void* head = g_tls_sll_head[7];
|
||||
if (head != NULL) {
|
||||
fprintf(stderr, "[TLS_SLL_BUG] C7 found in TLS SLL! head=%p count=%u\n",
|
||||
head, g_tls_sll_count[7]);
|
||||
fprintf(stderr, "[TLS_SLL_BUG] This should NEVER happen - C7 is headerless!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TLS_SLL_BOX_H
|
||||
Reference in New Issue
Block a user