Skip to content

Commit 8638942

Browse files
committed
plan: C1 is closed --- the only true unknown in the list
Both layers located and fixed, shipping in openkal-llvm-runtime 0.15.0. The second layer: `__thread` is emutls under `-femulated-tls`, emutls keeps its per-thread blocks behind a pthread key of its own, and that key's destructor releases this thread's block before libc++abi's runs. Criterion: `&dtors` differs three times in one thread. It was closed by the criterion the finding document itself wrote down. And the hypothesis that document recorded as refuted was correct --- the probe created its own key before first touching a thread-local, and musl runs key destructors in creation order, so emutls outlived it. The predicate was right; the object's construction excluded the condition under test.
1 parent 0e10e35 commit 8638942

1 file changed

Lines changed: 28 additions & 6 deletions

File tree

.agents/docs/2026-09-21-openkal-ecosystem-completion-and-acceptance.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,17 +273,39 @@ musl 0.19.0 必须先登记进索引。
273273
274274
#### C1 — `__cxa_thread_atexit`
275275
276-
**状态**:第一层可修但**不能只修第一层**;第二层未定位。记录:
277-
`.agents/docs/2026-09-20-cxa-thread-atexit-finding.md`。
276+
**状态**:**两层都已定位并修复**,发在 `openkal-llvm-runtime@0.15.0`。记录:
277+
`.agents/docs/2026-09-20-cxa-thread-atexit-finding.md` §7。
278+
279+
**第二层的真因**:`__thread DtorList* dtors` 在 `-femulated-tls` 下由 emutls 提供,而
280+
emutls 把每线程的块挂在它自己的一个 pthread key 后面;那个 key 的析构先释放了本线程的块,
281+
之后每次读都新分配一个**清零**的块。判据是同一线程里 `&dtors` 三次不同
282+
(`...6a8` / `...6c8` / `...708`)。
283+
284+
**本清单里「唯一的未知数」是被它自己写下的判据关掉的**——发现文档 §6 写的第一步就是
285+
「在 fallback 里打一行,看 `run_dtors` 到底有没有被调用」。它被调用了,而链表是空的。
286+
287+
**并且:§4 那条被判为「否」的假设其实是对的。** 那次探针的 `pthread_key_create` 排在第一次
288+
访问 `thread_local` **之前**,而 musl 按创建顺序调 key 析构,于是 emutls 反而活得更久,
289+
读到了期望值。真实情形顺序相反。**一个探针报不出它被构造成不会发生的那个顺序**——谓词是
290+
对的,对象的构造把被测条件排除掉了。
291+
292+
**修法**:链表存进 key 自己的值(析构函数本来就被交给它),零新机制。
278293
279294
只补符号会把一个**构建期的响亮失败**换成一个**运行期的静默失败**:链接过了,
280295
`thread_local` 的析构不跑。补丁试过并**主动回退**,因为验证显示析构确实没执行。
281296
282-
**判据**:最小复现(五行,文档里有)在 `x86_64-windows-gnu` 上**链接通过且析构函数
283-
真的执行**——两个条件缺一不可。只断言链接通过是错的判据。
297+
**判据(已通过)**:`examples/cxx` 两条断言,两个目标:
298+
299+
```
300+
ok: a thread_local is constructed in a spawned thread
301+
ok: and its destructor runs when that thread ends
302+
```
303+
304+
`x86_64-linux-gnu` 与 `x86_64-windows-gnu`(wine)均 `failures: 0`。只断言链接通过、
305+
或只断言构造发生,都会同时放过两层——这正是当初决定不发第一层补丁的理由,现在它变成了
306+
判据本身的形状。
284307
285-
**阻塞**:第二层未定位(emutls 在 PE 上的注册路径)。这是本清单里**唯一一个真正的
286-
未知数**。
308+
**阻塞**:无。本清单里唯一那个真正的未知数已关闭。
287309
288310
#### C2 — `linux/` uapi 头(curl, cmp-module)
289311

0 commit comments

Comments
 (0)