167 lines
5.3 KiB
Markdown
167 lines
5.3 KiB
Markdown
|
|
# C7 (1024B) TLS SLL Corruption Root Cause Analysis
|
|||
|
|
|
|||
|
|
## 症状
|
|||
|
|
|
|||
|
|
**修正後も依然として発生**:
|
|||
|
|
- Class 7 (1024B)でTLS SLL破壊が継続
|
|||
|
|
- `tiny_nextptr.h` line 45を `return 1u` に修正済み(C7もoffset=1)
|
|||
|
|
- 破壊がClass 6からClass 7に移動(修正の効果はあるが根本解決せず)
|
|||
|
|
|
|||
|
|
**観察事項**:
|
|||
|
|
```
|
|||
|
|
[TLS_SLL_POP_INVALID] cls=7 head=0x5d dropped count=1
|
|||
|
|
[TLS_SLL_POP_INVALID] cls=7 last_push=0x7815fa801003 ← 奇数アドレス!
|
|||
|
|
[TLS_SLL_POP_INVALID] cls=7 head=0xfd dropped count=2
|
|||
|
|
[TLS_SLL_POP_INVALID] cls=7 last_push=0x7815f99a0801 ← 奇数アドレス!
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
1. headに無効な小さい値(0x5d, 0xfd等)が入る
|
|||
|
|
2. `last_push`アドレスが奇数(0x...03, 0x...01等)
|
|||
|
|
|
|||
|
|
## アーキテクチャ確認
|
|||
|
|
|
|||
|
|
### Allocation Path(正常)
|
|||
|
|
|
|||
|
|
**tiny_alloc_fast.inc.h**:
|
|||
|
|
- `tiny_alloc_fast_pop()` returns `base` (SuperSlab block start)
|
|||
|
|
- `HAK_RET_ALLOC(7, base)`:
|
|||
|
|
```c
|
|||
|
|
*(uint8_t*)(base) = 0xa7; // Write header at base[0]
|
|||
|
|
return (void*)((uint8_t*)(base) + 1); // Return user = base + 1
|
|||
|
|
```
|
|||
|
|
- User receives: `ptr = base + 1`
|
|||
|
|
|
|||
|
|
### Free Path(ここに問題がある可能性)
|
|||
|
|
|
|||
|
|
**tiny_free_fast_v2.inc.h** (line 106-144):
|
|||
|
|
```c
|
|||
|
|
int class_idx = tiny_region_id_read_header(ptr); // Read from ptr-1 = base ✓
|
|||
|
|
void* base = (char*)ptr - 1; // base = user - 1 ✓
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**tls_sll_box.h** (line 117, 235-238):
|
|||
|
|
```c
|
|||
|
|
static inline bool tls_sll_push(int class_idx, void* ptr, uint32_t capacity) {
|
|||
|
|
// ptr parameter = base (from caller)
|
|||
|
|
...
|
|||
|
|
PTR_NEXT_WRITE("tls_push", class_idx, ptr, 0, g_tls_sll[class_idx].head);
|
|||
|
|
g_tls_sll[class_idx].head = ptr;
|
|||
|
|
...
|
|||
|
|
s_tls_sll_last_push[class_idx] = ptr; // ← Should store base
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**tiny_next_ptr_box.h** (line 39):
|
|||
|
|
```c
|
|||
|
|
static inline void tiny_next_write(int class_idx, void *base, void *next_value) {
|
|||
|
|
tiny_next_store(base, class_idx, next_value);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**tiny_nextptr.h** (line 44-45, 69-80):
|
|||
|
|
```c
|
|||
|
|
static inline size_t tiny_next_off(int class_idx) {
|
|||
|
|
return (class_idx == 0) ? 0u : 1u; // C7 → offset = 1 ✓
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static inline void tiny_next_store(void* base, int class_idx, void* next) {
|
|||
|
|
size_t off = tiny_next_off(class_idx); // C7 → off = 1
|
|||
|
|
|
|||
|
|
if (off == 0) {
|
|||
|
|
*(void**)base = next;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// off == 1: C7はここを通る
|
|||
|
|
uint8_t* p = (uint8_t*)base + off; // p = base + 1 = user pointer!
|
|||
|
|
memcpy(p, &next, sizeof(void*)); // Write next at user pointer
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 期待される動作(C7 freelist中)
|
|||
|
|
|
|||
|
|
Memory layout(C7 freelist中):
|
|||
|
|
```
|
|||
|
|
Address: base base+1 base+9 base+2048
|
|||
|
|
┌────┬──────────────┬───────────────┬──────────┐
|
|||
|
|
Content: │ ?? │ next (8B) │ (unused) │ │
|
|||
|
|
└────┴──────────────┴───────────────┴──────────┘
|
|||
|
|
header ← ここにnextを格納(offset=1)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- `base`: headerの位置(freelist中は破壊されてもOK - C0と同じ)
|
|||
|
|
- `base + 1`: next pointerを格納(user dataの先頭8バイトを使用)
|
|||
|
|
|
|||
|
|
### 問題の仮説
|
|||
|
|
|
|||
|
|
**仮説1: header restoration logic**
|
|||
|
|
|
|||
|
|
`tls_sll_box.h` line 176:
|
|||
|
|
```c
|
|||
|
|
if (class_idx != 0 && class_idx != 7) {
|
|||
|
|
// C7はここに入らない → header restorationしない
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
C7はC0と同様に「freelist中はheaderを潰す」設計だが、`tiny_nextptr.h`では:
|
|||
|
|
- C0: `offset = 0` → base[0]からnextを書く(header潰す)✓
|
|||
|
|
- C7: `offset = 1` → base[1]からnextを書く(header保持)❌ **矛盾!**
|
|||
|
|
|
|||
|
|
**これが根本原因**: C7は「headerを潰す」前提(offset=0)だが、現在は「headerを保持」(offset=1)になっている。
|
|||
|
|
|
|||
|
|
## 修正案
|
|||
|
|
|
|||
|
|
### Option A: C7もoffset=0に戻す(元の設計に従う)
|
|||
|
|
|
|||
|
|
**tiny_nextptr.h** line 44-45を修正:
|
|||
|
|
```c
|
|||
|
|
static inline size_t tiny_next_off(int class_idx) {
|
|||
|
|
// Class 0, 7: offset 0 (freelist時はheader潰す)
|
|||
|
|
// Class 1-6: offset 1 (header保持)
|
|||
|
|
return (class_idx == 0 || class_idx == 7) ? 0u : 1u;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**理由**:
|
|||
|
|
- C7 (2048B total) = [1B header] + [2047B payload]
|
|||
|
|
- Next pointer (8B)はheader位置から書く → payload = 2047B確保
|
|||
|
|
- Header restorationは allocation時に行う(HAK_RET_ALLOC)
|
|||
|
|
|
|||
|
|
### Option B: C7もheader保持(現在のoffset=1を維持し、restoration追加)
|
|||
|
|
|
|||
|
|
**tls_sll_box.h** line 176を修正:
|
|||
|
|
```c
|
|||
|
|
if (class_idx != 0) { // C7も含める
|
|||
|
|
// All header classes (C1-C7) restore header during push
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**理由**:
|
|||
|
|
- 統一性:全header classes (C1-C7)でheader保持
|
|||
|
|
- Payload: 2047B → 2039B (8B next pointer)
|
|||
|
|
|
|||
|
|
## 推奨: Option A
|
|||
|
|
|
|||
|
|
**根拠**:
|
|||
|
|
1. **Design Consistency**: C0とC7は「headerを犠牲にしてpayload最大化」という同じ設計思想
|
|||
|
|
2. **Memory Efficiency**: 2047B payload維持(8B節約)
|
|||
|
|
3. **Performance**: Header restoration不要(1命令削減)
|
|||
|
|
4. **Code Simplicity**: 既存のC0 logicを再利用
|
|||
|
|
|
|||
|
|
## 実装手順
|
|||
|
|
|
|||
|
|
1. `core/tiny_nextptr.h` line 44-45を修正
|
|||
|
|
2. Build & test with C7 (1024B) allocations
|
|||
|
|
3. Verify no TLS_SLL_POP_INVALID errors
|
|||
|
|
4. Verify `last_push` addresses are even (base pointers)
|
|||
|
|
|
|||
|
|
## 期待される結果
|
|||
|
|
|
|||
|
|
修正後:
|
|||
|
|
```
|
|||
|
|
# 100K iterations, no errors
|
|||
|
|
Throughput = 25-30M ops/s (current: 1.5M ops/s with corruption)
|
|||
|
|
```
|