Skip to content

Commit 7b3b540

Browse files
committed
docs: record where 'refuse without an authority' was too tight
§9.6. The design's rule -- no authority, no payload-first -- assumed a machine always has at least one of the compatibility sources. All three are artifacts some earlier mechanism wrote, and a machine can legitimately have none, at which point refusing hands the artifact the HOST loader: worse than guessing a version, because it leaves the sandbox entirely. The axis is whether there is anything to choose between, not whether mcpp may look. One payload is an answer; two are the incident.
1 parent 9840ca9 commit 7b3b540

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

.agents/docs/2026-08-08-payload-version-and-contract-drift-design.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,27 @@ workspace 已经用掉 43%。`payload_ld` 现在只服务 clang-with-cfg 的 Pay
313313
`rel.native().rfind("..", 0)` 在 Windows 上**编译不过**(`native()``wstring`),所有
314314
Windows job 直接挂;而且它在能编译的地方语义也错 —— 名叫 `..cache` 的目录并不是逃逸。
315315
包含关系是**路径分量**的问题,`path_is_under` 按分量问。
316+
317+
### 9.6 「拒绝」的边界:一个 payload 是答案,两个才是问题
318+
319+
§3.2 把判据写成「没有权威就拒绝走 payload-first」。落地后发现这条**收得过紧**
320+
321+
所有兼容来源(gcc 的 `specs`、clang 的 `.cfg`、编译器自身的 `PT_INTERP`)都是**某个更早
322+
的机制写出来的东西**,而一台机器可以合法地一个都没有。这时按 §3.2 的字面判据就该拒绝,
323+
产物于是拿宿主 loader —— 比「猜错版本」更糟,因为它连沙箱都出去了。
324+
325+
真正的轴不是「mcpp 能不能去看 payload 目录」,而是**有没有得选**:
326+
327+
- **恰好一个 glibc payload** ⇒ 没有选择可言。它是这套工具链产出的任何产物唯一可能绑定的
328+
运行时,拒绝等于拒答一个只有一个答案的问题。
329+
- **两个或以上** ⇒ 沉默。这正是事故本身的形状,必须由 subos 来定。
330+
331+
这与被移除的旧规则的区别是决定性的:旧规则在**有得选**的时候按 `readdir` 顺序选,而且
332+
一直到装进第二个 payload 之前都看起来是对的。
333+
334+
另外,记录下来的 loader 路径可能指向 subos **视图**(`<home>/subos/default/lib/ld-linux-…`)
335+
而不是 payload —— 视图路径里根本没有版本段。解析前先 canonical 化(R6:产物绑 payload,
336+
不绑可变视图)。
337+
338+
验证方式:把 gcc 的 `specs` 挪开**并且**把 gcc 自身的 `PT_INTERP` 改指宿主 loader,即三条
339+
兼容来源全部失效,binding 仍解析得出,产物仍拿 payload loader。

0 commit comments

Comments
 (0)