1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! RQ-58-FLAKE (#977) — the compile-then-parse guard the integration tests owe.
//!
//! Every byte-gate in `crates/synth-cli/tests/` has the same shape: run
//! `synth compile -o <path>`, then read `<path>` back and parse it as an ELF.
//! Two things go wrong with that shape, and only one of them is loud.
//!
//! **Loud.** The read lands on something that is not an ELF and `object`
//! reports `Could not read file magic` (#960, #974, #977). It looks like an
//! assertion failure in a file the PR never touched, so it reads as noise.
//!
//! **Silent, and the reason this module exists.** The read lands on a
//! *previous run's* ELF. `synth compile` opens the output with
//! `File::create` — truncate-then-write — so a failed or half-finished
//! compile leaves either nothing, a zero-length file, or the bytes that were
//! already there. Parse those and the gate passes on evidence it did not
//! produce. v0.56 lived through exactly this with the opposite sign: a
//! compile failed, `-o` wrote nothing, the previous run's `.o` was still on
//! disk, and executing it looked like a fresh miscompile.
//!
//! So the contract here is: **nothing parses an artifact until the artifact is
//! proven to be this invocation's output.** In order —
//!
//! 1. the output path is removed before the compile runs,
//! 2. the compile's exit status is asserted, carrying synth's own stderr,
//! 3. the file is asserted to exist,
//! 4. the file is asserted non-empty,
//!
//! and only then are the bytes handed back. A bad compile reports as a bad
//! compile, at the compile, with the compiler's message — not as a parse error
//! twenty lines later, and never as a pass.
//!
//! Freshness is additionally guaranteed *by construction*: [`unique_artifact`]
//! hands out a path that is unique per call (pid + a process-wide counter), so
//! no two compiles — in different libtest threads of one binary, or in two
//! binaries/CI runs sharing one `/tmp` — can ever name the same file. That is
//! the collision that produced #977: `shift_mask_elide_686.rs` derived its
//! output name from `(fixture, relocatable, flag)` only, and its two `#[test]`
//! fns walk the *same* corpus with the *same* flag values on parallel libtest
//! threads, so both wrote and read one path. Under concurrency this
//! reproduced `Could not read file magic` in 10 of 48 runs.
//!
//! Deliberately NOT checked: mtime. Filesystem timestamp granularity is coarse
//! enough that an mtime freshness test would become its own flake source.
//! Remove-first plus a unique path is stronger and has no clock in it.
//!
//! The guards are observed firing by the `artifact_guard_*` tests in
//! `shift_mask_elide_686.rs` — a guard nobody watched fire is not a guard.
use ;
use Command;
use ;
/// Process-wide, so two calls in two libtest threads cannot collide.
static SEQ: AtomicU64 = new;
/// A path no other call — in this process or any other — will produce.
///
/// `tag` is a human-readable hint (test/fixture name); it only has to be
/// filesystem-safe, uniqueness comes from the pid and the counter.
/// Prove `path` is a readable, non-empty file and return its bytes.
///
/// Split out from [`compile_artifact`] so the empty/missing guards can be
/// exercised directly, without having to persuade a compiler to emit a
/// zero-byte object.
/// Run a `synth compile` (or any producer) that writes to `out`, and return the
/// artifact's bytes only if this invocation actually produced them.
///
/// `cmd` must already carry `-o <out>`. The path is removed first, so a stale
/// artifact from an earlier run can never be mistaken for this one's output.
/// [`compile_artifact`], panicking with `ctx` prefixed — the ergonomic form for
/// a byte gate whose only sane response to a failed compile is to stop. Leaves
/// the artifact in place for callers that need the path afterwards.
/// [`compile_artifact_or_panic`] for gates that only want the bytes: the
/// artifact is deleted once read. Per-call unique paths mean nothing is ever
/// reused, so without this the temp dir would grow by one file per compile on a
/// long-lived (self-hosted) runner.