Skip to content

v1.3.0 — Threads, awaited children, and the syscall boundary

Choose a tag to compare

@yottayoshida yottayoshida released this 08 Sep 23:51
· 633 commits to main since this release
2d49470

Five days, 115 commits and twenty-two entries since v1.2.0. Three trace-contract versions in one release — v14, v15, v16 — each one widening what Sideeye will judge rather than refuse. The full section is CHANGELOG.md at this tag; this page names what to read first.

Read this first if a target of yours was refused for threads or for a helper process. Both refusals have moved.

  • One writing thread per process is judged, however many threads the target created (contract v16, ADR 0055). Until now any thread refused the run. What actually stood in the way was the shim's process-wide state, the oracle reader calling a thread a child, and a record that named its process only; each record names its thread now, the shim keeps per-thread slots keyed by gettid() (0.09 µs per interposed call, measured), and a thread needs no oracle. What still refuses, by name: a second thread of the same process writing the judged directory, a run under --oracle-fs-usage (macOS, #544), and the 65th thread (#543). Measured on the targets behind the wall: sqlfluff PASS, bundler FAIL, vips FAIL, zstd PASS under --observe syscalls; beets refuses correctly — two of its threads open library.db. Threads that take turns are the next stage (#539).
  • A child that takes turns with the judged directory is explored and judged (contract v15, ADR 0053). A crash point is an address in the run, not in a process, so an awaited child's write can be killed at like any other. Two processes whose operations overlap, a writer nothing waited for, and a writer the shim never loaded still refuse, each with its own sentence.
  • --observe syscalls counts the write family at the kernel boundary (contract v14, ADR 0052), reaching the writes libc issues from inside fwrite and raw syscall(SYS_write, …). Linux only, behind a flag, 1.6–1.8 µs per trap. metaflac and fontforge go from oracle_missed_operation to verdicts; mutool, after the close exemption below, reaches FAIL there. Fourteen previously judged targets re-run in both modes reach the same verdict in both. One limit is unlike every other on the README's list: the seccomp filter is inherited across exec and a statically linked helper dies on its first write — check that before reaching for the flag.
  • That mode's oracle now watches the run it judges (ADR 0054): the kernel's SIGSYS line lets the reader retract the refused call, so oracle_verified is earned honestly and the two-run arrangement is gone. The field it carried in the meantime, oracle_verified_across_runs, is withdrawn — it was added after v1.2.0 and never shipped in a tagged binary; the freeze page records the break.

Refusals that were wrong, fixed. An unplaceable close no longer refuses a run (ADR 0003 §2 amended — the whole mutool wall was one close wide, and two refusal sites that did not exist were added with it, #522). A shell resolving a bare name down PATH is no longer read as seven image changes (ADR 0018 amended); hnb reaches a verdict for it. The processes account stops saying two things that were false, and four published statements of a rule that is false as stated are corrected. A failing --setup keeps what it wrote and the refusal quotes its last line beside the file (#483); an unplaceable operation names its descriptor (#485). Two ways a breached loop-closure seal came back clean are closed (#511, #514).

Two fixes the release's own CI day forced. A child the engine forked and could not arrange before exec — setpgid or a dup2 failing — used to exit 126 in silence; it now writes one line on the engine's stderr naming the call and the errno, every dup2 before exec retries EINTR, and the six sentences that read a 126 say the two indistinguishable causes instead of a state difference or "declare --expect-status" (#546). And the macOS fs_usage reader no longer refuses a run over a line it cannot attribute to anyone when that line reads only — a daemon's file named in combining characters had ended such a line inside the name, its tail arriving on the next physical line (#547 and #548, ADR 0031 narrowed).

Records. The loop-closure judge is seen refusing on every channel it declares (#63; thirteen refusals, ten mutations with exact attribution). The cohort ledger's prose counts are recomputed and drift is red in CI (#342). A refusal on an operation that is not an executable image names the define, not the shim (#481, #482, ADR 0051). The dogfood ledger gains slates 2 and 3 (isort PASS as the positive control; fonttools, beancount, pyupgrade, libjpeg-turbo filed upstream) and two measurements of ImageMagick's patches for #8939 — the third patch closes both reported items and breaks preserve-timestamp.

Upgrading. Saved cases from v13 replay as case_no_longer_applies; re-record. A v15 shim under this engine refuses contract_version_mismatch. The unknown_reason closed set is unchanged at 34 members.