Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/todo/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ nowhere else. This file is a list, not an order and not a log.
| | open | partially done | done | total |
|---|---|---|---|---|
| measurement | 5 | 1 | 0 | 6 |
| infrastructure | 7 | 0 | 2 | 9 |
| infrastructure | 6 | 0 | 3 | 9 |
| blocked | 7 | 0 | 2 reclassified | 9 |
| **total** | **19** | **1** | **2 done, 2 reclassified** | **24** |
| **total** | **18** | **1** | **3 done, 2 reclassified** | **24** |

By priority, across the open and partially-done rows:

| priority | count |
|---|---|
| high | 6 |
| high | 5 |
| medium | 7 |
| low | 0 |
| blocked (no priority, because a machine unblocks these rather than a decision) | 7 |
Expand All @@ -45,7 +45,7 @@ By priority, across the open and partially-done rows:
| T-15 | [A corpus test with a fresh process per library](infrastructure.md) | infrastructure | medium | open |
| T-16 | [Delete the path that would mask the failure](infrastructure.md) | infrastructure | medium | open |
| T-17 | [The IBT property note is documented and is not there](infrastructure.md) | infrastructure | medium | open |
| T-18 | [There is no release](infrastructure.md) | infrastructure | high | open |
| T-18 | [There is no release](infrastructure.md) | infrastructure | high | done |
| B-01 to B-09 | [the blocked list](blocked.md), nine rows. ⚠ **Two of them are not blocked**; the correction is at the foot of that file and the work is T-02 and T-06 | blocked | n/a | 7 open, 2 reclassified |

---
Expand Down
112 changes: 72 additions & 40 deletions docs/todo/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,63 +8,95 @@

## Where the work is right now

[v0.2.6](https://github.com/pkgforge-dev/cross-libc-dlopen/releases/tag/v0.2.6) is
[v0.2.9](https://github.com/pkgforge-dev/cross-libc-dlopen/releases/tag/v0.2.9) is
published.

| workflow | latest on `main` |
|---|---|
| `gates` | ✅ |
| `secret-sweep` | ✅ |
| `release` | ✅ on `v0.2.6` |

**This branch fixes the host lookup that stopped on a library the loader would
refuse, on branch `fix/gl-fwd-wrong-class`, and needs a release once merged.
`v0.2.6` was released from `main` before it, so no released artefact carries
the fix.**
| `release` | ✅ on `v0.2.9` |

`v0.2.9` adds the three NixOS host directories: `/run/opengl-driver/lib` and
`/run/current-system/sw/lib` join the shim's fixed host list, the assembled
`--library-path`, and the libva `<dir>/dri` list. NixOS is neither FHS nor a
host that writes `/etc/ld.so.conf`, so before this each of the three failed
differently and silently.

⚠ **The three cases ran in the container; no NixOS host was behind them.** E104,
E105 and E106 create `/run/opengl-driver/lib`, which needs root, so the container
suite runs all three and reports MATCH, which is why the local total is higher
than the previous release's. Where `/run` is not writable each SKIPS by name
instead. ⛔ **Nothing in this tree has run the shims on a NixOS host.** The cases
prove the lists carry the directories and that a library placed there is found;
they do not prove the directories are where a real NixOS system puts its GPU
userspace, and
[`../report/10-measured-versus-assumed.md`](../report/10-measured-versus-assumed.md)
does not yet carry that distinction. Writing it there is open work, not a
citation.

The mechanism was also confirmed here as an A/B independent of the suite: the
fake-libva contract run against the `v0.2.8` source prints `NO-DRIVER`, and
against the shipped source prints `DRIVER=NIX`. The published binaries carry
the directory strings.

`v0.2.8` remains the first release carrying the ppc64le resolver frame repair
(PR #60). `v0.2.7` and earlier ship a `gl-fwd.so` whose `glfwd_resolve_asm`
saved r5 and r6 where the C callee writes its caller's LR and TOC slots, so the
first call of any GL entry point taking a third or fourth integer argument was
handed garbage. Issue #59 is the report.

---

## ⛔ The work order

### 1. `glfwd_try_soname` must not stop on a library the loader will refuse
### 1. `glfwd_try_vendor` accepts a matching filename without checking its class

`glfwd_try_soname` skips a candidate of the other ELF class, and
`glfwd_try_vendor` does not. A host whose only vendor library is the wrong
class is therefore reported as having one. It is a different path, reached only
when the bundle carries a dispatcher, so it needs a bundled-dispatcher case to
measure. Nothing in this session's change touches it.

`glfwd_try_soname` took the first directory in which its own soname existed, and
`glfwd_each_dir` stopped the walk there. A candidate of the other ELF class
cannot load, so a host whose own answer named a 32bit library directory first
produced a target that could not load, and the directory after it was never
reached. Reproduced by removing `libGL.so.1` from the host-drivers demo AppDir,
which forces the host path, and naming the 32bit directory first with
`CROSS_LIBC_DLOPEN_GL_HOST_DIR`.
### 2. Wire `make gl-fwd-qemu-check` into a runner

The repair reads the candidate's ELF ident and skips a candidate of the other
class, so the walk continues. `docs/report/09-the-second-boundary.md` 9.21 has
the transcript, E103 is the case, and `docs/report/08-test-results.md` owns the
new totals.
The case that caught the ppc64le frame exists and fails on the old source, but
nothing runs it: `gates.yml` builds ppc64le and runs
`scripts/verify-artifacts.sh`, which never executes a trampoline. The target is
run by hand today. ⚠ This is issue #59's first loose end and it is the reason
that class of bug reached a release at all.

### 2. What is still open
### 3. The stale totals in `docs/ground-truth.md`

`glfwd_try_vendor` accepts a matching filename without checking its class, so a
host whose only vendor library is the wrong class is reported as having one. It
is a different path, reached only when the bundle carries a dispatcher, and it
needs a bundled-dispatcher case to measure. Nothing in this session's change
touches it.
It still states the evidence table as 22/22 (issue #45). The home for the
totals is [`../report/08-test-results.md`](../report/08-test-results.md), which
carries the current pair. This is the last document of the release-shaped
staleness class that issue #46 opened, and T-18 is closed.

---

## ⚠ What a new session should distrust

- **E103 forces the order through `/etc/ld.so.conf.d`, and a host whose own
answer puts the 64bit directory first never reaches the defect.** Debian 10
is such a host: `libc6-i386` names `/usr/lib32` and `/lib32` in
`zz_i386-biarch-compat.conf`, which sorts after `x86_64-linux-gnu.conf`. So
the case pins the predicate, not a claim about any one distribution.
- **The host-drivers demo AppDir bundles the glvnd dispatcher, so the shim
takes the bundled path on a glvnd host and never reaches the host lookup.**
Removing `libGL.so.1` from that AppDir is what exposes the path, and the
deletion is a harness step rather than a change to any shipped AppImage.
- **A Qt6 GLX path does not link `libGL.so.1`.** `libqxcb-glx-integration.so`
and `libQt6Gui.so.6` need `libGLX.so.0` and `libOpenGL.so.0`, so which arm a
Qt application reaches depends on what else in its AppDir links
`libGL.so.1`. Check `readelf -d` before assuming.
- **`docs/todo/INDEX.md` carries the counts it carried before this session.**
Reconcile them if an entry moves.
- **The scheduled `appimage-suite` on `main` is red, and the failure is
upstream's, not this tree's.** Both architectures fail at
`experiments/41-extract.sh` with `no dispatcher slot in AppDir/lib.`: the
`demo` release of `Anylinux-AppImages` no longer carries
`cross-libc-dlopen.so` or `foreign-dlopen.so` in `lib/`. The extraction
refuses rather than guessing, which is what it was built to do. Verify against
the upstream asset before treating it as a defect here.
- **The release gate is not the wide suite.** `release.yml` runs the evidence
table on x86_64 and aarch64 and then builds all five architectures. It does
not run `run-appimage.sh`, so a green `v0.2.9` does not mean the AppImage
suite is green.
- **The NixOS directories are a host class nobody has run.** The three cases
prove the lists carry the directories and that a library placed there is
found. No NixOS host has been behind the shims, and
[`../report/10-measured-versus-assumed.md`](../report/10-measured-versus-assumed.md)
is where that distinction belongs if it is not already written there.
- **A tag's tree, not its commit, is what CI tested.** `v0.2.8` and `v0.2.9`
are both squashed commits, so their hashes appear in no run. Check
`git rev-parse <tag>^{tree}` against the PR head's tree before concluding a
tag went untested.
- **`docs/todo/INDEX.md`'s counts are checked by hand.** `sh scripts/check-drift.sh`
reconciles the rows against the entries and does not check the totals, so a
future closure moves numbers no gate reads.
50 changes: 49 additions & 1 deletion docs/todo/infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ cites exists, and every module a tool imports is reachable from that tool's own

- **Source.** The operator, at the end of the port session.
- **Category** infrastructure, **Priority** high, **Effort** medium,
**Status** open
**Status** done
- **Problem.** `scripts/build.sh` produces verified artefacts and a manifest,
and nothing publishes them. A consumer who wants `gl-fwd.so` has to build it,
which means having a container engine and this repository.
Expand All @@ -397,3 +397,51 @@ cites exists, and every module a tool imports is reachable from that tool's own
- **Prove.** A release exists whose assets' checksums match
`build-manifest.json` for both architectures, and whose body was not written
by hand.

### Correction: the title was true when it was written and has not been since v0.1.0

The title is kept because it is how this entry has been cited everywhere else.
The premise above is superseded, and the correction is written here rather
than edited into it.

`v0.2.8` is published, and so are the eight releases before it. The workflow
that publishes them is [`release.yml`](../../.github/workflows/release.yml),
which builds **five** architectures, not the two the premise names: x86_64,
aarch64, riscv64, ppc64le and loongarch64. The aarch64 premise in particular is
disproved on every release: the `build and package aarch64` job cross-compiles
it on the floor and the `evidence table (aarch64)` job runs the suite on
`ubuntu-24.04-arm`.

**Acceptance command and its output**, run against the published release:

```console
$ gh release list --repo pkgforge-dev/cross-libc-dlopen --limit 3
v0.2.8 Latest v0.2.8 2026-10-22T10:48:20Z
v0.2.7 v0.2.7 2026-09-24T18:29:17Z
v0.2.6 v0.2.6 2026-09-13T10:01:17Z

$ gh release download v0.2.8 --repo pkgforge-dev/cross-libc-dlopen
$ for a in x86_64 aarch64 riscv64 ppc64le loongarch64; do
> sha256sum -c cross-libc-dlopen-$a.sha256 --quiet && echo "$a: ok"
> done
x86_64: ok
aarch64: ok
riscv64: ok
ppc64le: ok
loongarch64: ok

$ tar -tf cross-libc-dlopen-x86_64.tar | grep -c /
0
```

The release carries 40 assets. Every one of the five `.sha256` files verifies
against the assets it names, both archives per architecture are flat (no
nested directory, as the entry required), and the manifest inside the archive
matches the loose files beside it. The body was generated by
[`../../scripts/release-notes.sh`](../../scripts/release-notes.sh) from
`build-manifest.json`, so no checksum in it was typed.

⚠ **What the closure does not prove.** The ancestor refusal in `release.yml`
passes on every tag because every tagged commit is on `main`; it has never been
seen to refuse a tag that was not. That remains T-10's subject, not this
entry's.
Loading