testbins is the versioned binary corpus consumed by NeverD integration tests.
It owns the source snapshots, purpose-built probes, compilers, validation,
manifests, and generated binaries. NeverD treats the repository as read-only
test data and does not rebuild these binaries.
Every binary is compiled from the sources in this repository by GitHub Actions. Nothing is uploaded from a developer's machine.
| Line | Formats | Manifest | Schema | Workflow |
|---|---|---|---|---|
windows-eh |
PE | manifests/windows-eh.json |
schema/windows-eh-manifest.schema.json |
build-windows-eh.yml |
rust-eh |
ELF, PE, Mach-O | manifests/rust-eh.json |
schema/rust-eh-manifest.schema.json |
build-rust-eh.yml |
cxx-itanium-eh |
ELF, Mach-O, PE | manifests/cxx-itanium-eh.json |
schema/cxx-itanium-eh-manifest.schema.json |
build-cxx-itanium-eh.yml |
objc-eh |
Mach-O | manifests/objc-eh.json |
schema/objc-eh-manifest.schema.json |
build-objc-eh.yml |
ada-d-eh |
ELF | manifests/ada-d-eh.json |
schema/ada-d-eh-manifest.schema.json |
build-ada-d-eh.yml |
Each line follows the same shape: sources pinned in the repository, a matrix
script, a per-cell build script, a fragment merge, a strict JSON Schema, a
verifier that re-derives every claim from the bytes on disk, and a four-stage
workflow where only the publish job on a main push or manual main dispatch
is granted contents: write.
The Windows producer covers Microsoft SEH and C++ exception metadata across two toolchains and four canonical PE architectures:
| Toolchain | Architecture | C++ EH format | Cookie | Optimization | Cells |
|---|---|---|---|---|---|
| MSVC | x86-64 | EH3, EH4 | /GS-, /GS |
/Od, /O2 |
8 |
| clang-cl | x86-64 | EH3 | /GS-, /GS |
/Od, /O2 |
4 |
| MSVC | x86, ARM32, ARM64 | native | /GS-, /GS |
/Od, /O2 |
12 |
| clang-cl | x86, ARM64 | native | /GS-, /GS |
/Od, /O2 |
8 |
The complete matrix contains 32 cells. Twenty-four full-capability cells contain six PE files each. The eight host-native clang-cl x86/x86-64 cells contain three PE files each, for a canonical total of 168 artifacts.
x86 is the canonical name for the 32-bit i386 target; the corpus does not
duplicate it under two names. EH4 is the compressed Microsoft x64 C++ EH
format and is produced only by MSVC. MSVC EH3 is forced with /d2FH4-, EH4 is
forced with /d2FH4, and the resulting runtime personality is verified.
clang-cl emits EH3 for the x64 Microsoft ABI and receives an explicit target
triple for every architecture. Non-x64 targets use their native Windows
exception ABI and are not mislabeled as EH3 or EH4.
Official clang-cl supports SEH __try on Windows x86, x86-64, and ARM64, but
not ARM32; its ARM32 backend also rejects C++ funclet EH. The producer therefore
does not advertise an ARM32 clang-cl exception cell. MSVC supplies the ARM32 SEH
and C++ EH artifacts. The capability-specific matrix is enforced by both the
producer and the complete-matrix verifier.
/GS and the C++ EH format are independent controls. The manifest records both
axes. Focused /GS probes must expose a nonzero, writable security cookie via
the PE Load Config directory; personality evidence is validated independently.
Every full-capability cell builds:
xcpt4,nested_collided,xframe_eh_exe, andxframe_eh_dllfrom the pinned Microsoft Windows SEH tests;seh_probe, which exercises nested__try,__except,__finally, and a buffer-protected function;cxx_eh_probe, which exercises typed and base catches, cleanup actions, nested regions, rethrow, and a buffer-protected catch.
The host-native clang-cl x86 and x86-64 cells omit xcpt4 and the xframe DLL/
EXE pair because those executables do not pass their own runtime tests under
clang-cl. nested_collided and both focused probes are still built and
executed. Cross-target clang-cl ARM64 retains all structurally validated images.
The imported source snapshot is pinned by full commit and per-file SHA-256 in
sources/windows-seh-tests/UPSTREAM.json. Its license is retained in the
snapshot and under LICENSES/.
Both the directory and filename repeat every build axis. For example:
corpus/windows-eh/msvc/x86_64/fh4/gs/o2/abi-probe/
cxx_eh_probe-msvc-x86_64-fh4-gs-o2.exe
corpus/windows-eh/clang-cl/aarch64/native/no-gs/o0/abi-probe/
cxx_eh_probe-clang-cl-aarch64-native-no-gs-o0.exe
The canonical manifest is manifests/windows-eh.json. Schema version 2 records
the exact compiler and linker identities per artifact, target triple, flags,
execution status, hash, size, structural PE evidence, and NeverD validation
level.
exception-graph: x64 artifacts must produce non-malformed normalized SEH or C++ exception graphs with the declared personalities and minimum graph size.unwind-only: ARM32 and ARM64 must produce bounded, non-malformed table unwind records. Their language payload normalization is tracked separately.load-only: x86 must load with the correct architecture. Its registration- chain language metadata is not falsely reported as table-based reconstruction.
x86 and x86-64 executables run on the hosted x64 Windows runner before
publication. ARM32 and ARM64 are cross-built and are not claimed to have run
natively; the producer instead verifies COFF machine values, exception
directories, .pdata runtime-function entries, referenced unwind-data bodies
(including payloads merged by the linker into .rdata),
Load Config security-cookie pointers, sections, imports, hashes, and manifest
consistency. llvm-readobj --unwind
provides an additional independent producer check for ARM artifacts.
Rust has no unwind table format of its own. On every non-MSVC target it emits an
Itanium LSDA with rust_eh_personality, and on *-pc-windows-msvc it emits the
same __CxxFrameHandler3 tables C++ uses. The Rust producer therefore varies the
target first, because the target is what changes the format:
| Target | Object format | Unwind metadata | Runner | Executable runs? |
|---|---|---|---|---|
x86_64-unknown-linux-gnu |
ELF | .eh_frame + .gcc_except_table |
ubuntu-24.04 |
yes |
aarch64-unknown-linux-gnu |
ELF | .eh_frame + .gcc_except_table |
ubuntu-24.04 |
cross-built |
x86_64-pc-windows-msvc |
PE | .pdata + MSVC C++ EH tables |
windows-2022 |
yes |
x86_64-apple-darwin |
Mach-O | __unwind_info + __eh_frame |
macos-15 |
cross-built |
aarch64-apple-darwin |
Mach-O | __unwind_info + __eh_frame |
macos-15 |
yes |
Each target is crossed with two panic strategies (unwind, abort) and two
optimization levels (-C opt-level=0, -C opt-level=2), giving 20 cells. Every
cell builds both crates, for a canonical total of 40 artifacts.
aarch64-unknown-linux-gnu is linked with gcc-aarch64-linux-gnu;
x86_64-apple-darwin needs no extra tooling because the macOS SDK carries both
slices. Neither can be executed on its runner, and neither claims to have been.
The toolchain is pinned to an exact release in rust-toolchain.toml, and the
manifest records the rustc -vV release, commit hash, commit date, and LLVM
version that produced every artifact. Builds pass --remap-path-prefix, and the
verifier fails if the remapped checkout path is still findable in a published
binary.
Two dependency-free std crates under sources/rust-eh/, compiled by rustc
directly rather than through Cargo, so CI needs no registry and every flag in
the manifest is a flag the producer actually passed:
rust_eh_probe(bin) holds aDropvalue across a panicking call, callsstd::panic::catch_unwind, nests drop scopes, crossesextern "C"andextern "C-unwind"boundaries, and reaches four distinctcore::panickingentry points: an explicitpanic!, anunwrap()onNone, an integer overflow, and both an array index and a range slice out of bounds.rust_eh_cdylib(cdylib) puts the same machinery behind C-ABI exports, which is where theextern "C"abort-on-unwind guard actually matters.
-C overflow-checks=on is passed at every optimization level, because rustc
otherwise ties overflow checks to debug assertions and drops the arithmetic
panic once optimizing.
-C panic=abort compiles the producer's own frames with no landing pads at all,
which is what neverd.expect_no_landing_pads asserts and what every zeroed
minimum in those artifacts records.
It does not empty the image. The prebuilt standard library was compiled to
unwind, so an aborting artifact still carries .eh_frame, an except table,
rust_eh_personality, and _Unwind_Resume. Exactly one thing disappears:
_Unwind_RaiseException is referenced only by the panic_unwind runtime, which
an aborting build does not link. The manifest claims that absence and nothing
more, and the verifier proves it from the symbol table.
panic-graph: unwinding artifacts must produce classified Rust landing pads with the declared personality, including acatch_unwindboundary.unwind-only: aborting artifacts must produce bounded, non-malformed unwind records, and no Rust panic semantics are claimed for them.
The MSVC minimums are deliberately lower than the Itanium ones. A Rust frame on
*-pc-windows-msvc is spelled with the same tables as a C++ frame, and the only
thing that separates them is a catch naming the unmangled rust_panic type
descriptor. A frame that merely runs Drop glue is therefore not attributable
to Rust, so drop-glue frames, abort guards, and panic sites are not claimed
there. The rust_panic descriptor itself is asserted as a required string,
because it is the one piece of Rust identity a stripped PE still carries.
Both the directory and the filename repeat every build axis:
corpus/rust-eh/x86_64-unknown-linux-gnu/unwind/o2/bin/
rust_eh_probe-x86_64-unknown-linux-gnu-unwind-o2
corpus/rust-eh/aarch64-apple-darwin/abort/o0/cdylib/
rust_eh_cdylib-aarch64-apple-darwin-abort-o0.dylib
Linux and macOS executables have no extension, so .gitattributes marks the
generated artifact directories as binary by path rather than by suffix.
The Itanium C++ ABI is one exception model with three containers and two producers, and the point of this line is that those combinations disagree with each other. The producer therefore varies the (toolchain, target) pair first, because that pair is what changes the format:
| Toolchain | Target | Unwind metadata | Personality | Runner | Executables run? |
|---|---|---|---|---|---|
| gcc | x86_64-linux-gnu |
.eh_frame + .gcc_except_table |
__gxx_personality_v0 |
ubuntu-24.04 |
yes |
| gcc | aarch64-linux-gnu |
.eh_frame + .gcc_except_table |
__gxx_personality_v0 |
ubuntu-24.04 |
cross-built |
| gcc | armv7-linux-gnueabihf |
.ARM.exidx + .ARM.extab |
__gxx_personality_v0 |
ubuntu-24.04 |
cross-built |
| gcc | x86_64-w64-mingw32 |
.pdata + .xdata |
__gxx_personality_seh0 |
ubuntu-24.04 |
cross-built |
| clang | x86_64-linux-gnu |
.eh_frame + .gcc_except_table |
__gxx_personality_v0 |
ubuntu-24.04 |
yes |
| clang | aarch64-linux-gnu |
.eh_frame + .gcc_except_table |
__gxx_personality_v0 |
ubuntu-24.04 |
cross-built |
| clang | armv7-linux-gnueabihf |
.ARM.exidx + .ARM.extab |
__gxx_personality_v0 |
ubuntu-24.04 |
cross-built |
| clang | x86_64-apple-darwin |
__unwind_info + __gcc_except_tab |
__gxx_personality_v0 |
macos-15 |
cross-built |
| clang | arm64-apple-darwin |
__unwind_info + __gcc_except_tab |
__gxx_personality_v0 |
macos-15 |
yes |
Each of the nine cells builds the same eight variants, for a canonical total of
72 artifacts: the main probe at -O0 and -O2, with and without symbols; the
exception-free control; the shared object at both optimization levels; and the C
probe.
Three of those differences are the reason the line exists. 32-bit ARM replaces
the DWARF chain outright, so there is no .eh_frame and no .gcc_except_table
anywhere -- the language specific data area is emitted inline in .ARM.extab,
indexed by .ARM.exidx. mingw-w64 keeps Itanium language semantics but
dispatches them through Windows SEH, so the frames live in .pdata/.xdata and
the personality is spelled seh0. Mach-O prefers compact unwind records and
keeps __eh_frame only for the frames that encoding cannot describe, so its
presence is not something the producer's flags decide and the manifest does not
claim it.
The corpus deliberately carries no -fsjlj-exceptions axis. The setjmp/longjmp
model is a configure-time property of the toolchain rather than a flag a
distribution compiler reliably honours, so a cell for it would be red more often
than it was informative. It is the obvious next axis if a producer that
guarantees it is ever pinned here.
The Linux cells pin GCC 13 and Clang 18 through the versioned apt packages they
install; the macOS cells pin Apple clang 17 by selecting a specific Xcode before
building. Every artifact records the release its driver actually reported, and
the verifier rejects a manifest whose recorded release is outside the pinned
series. Builds pass -ffile-prefix-map and -g0, and the verifier fails if the
remapped checkout path is still findable in a published binary.
Three sources under sources/cxx-itanium-eh/, with no dependency beyond the C
and C++ standard libraries:
cxx_eh_probe.cppcovers every shape one LSDA can take: catch by value, by const reference, and by pointer; a four-clause ladder;catch (...); a barethrow;; single and array cleanups; nested try; a base catch for a derived throw and the same through virtual inheritance; a throw through a lambda and through astd::function; anoexceptbody that can throw;returnfrom inside a try; a try inside a loop; and a function-scope static whose initializer can throw.cxx_eh_shared.cppputs the same machinery behind a shared-object boundary, including an entry that calls back out and catches what comes back.c_eh_probe.cis C compiled with-fexceptionsand__attribute__((cleanup)), which produces a__gcc_personality_v0table with cleanup actions and no type table at all. It links the shared object, so a C++ exception really does travel through its frames.
cxx_eh_probe_noexc is the same source as cxx_eh_probe compiled with
-fno-exceptions, so everything that disappears disappeared because of one
flag. Everything that raises sits behind CXX_EH_PROBE_EXCEPTIONS, including
the exception types, so the control has neither an except table nor the RTTI
that would identify one. It still passes -fasynchronous-unwind-tables: without
frame records there would be no metadata left to validate, and cfi-only would
be a claim about an empty image.
What it claims to lack is scoped to what the flag decides. On ELF and Mach-O it
asserts no except table and no __cxa_throw, because the C++ runtime is on the
other side of a dynamic dependency. The mingw cell links a static libstdc++
and therefore claims nothing: an except table there could belong to the runtime
rather than to the producer.
lsda-graph: a decoded call-site table, action chain, and type table reached through.gcc_except_table,__gcc_except_tab, or the SEH handler data.ehabi: the same graph reached through an.ARM.exidxindex and an inline.ARM.extabentry.cfi-only: bounded, non-malformed frame records, and nothing about exception semantics.
Both the directory and the filename repeat every build axis:
corpus/cxx-itanium-eh/gcc/armv7-linux-gnueabihf/o2/symtab/exe/
cxx_eh_probe-gcc-armv7-linux-gnueabihf-o2-symtab
corpus/cxx-itanium-eh/clang/arm64-apple-darwin/o0/symtab/shared/
libcxx_eh_shared-clang-arm64-apple-darwin-o0-symtab.dylib
A stripped artifact keeps no name of anything the producer compiled, so its
evidence is the mangled name of the type it throws: RTTI is data, and
15CxxEhProbeError survives a strip that removes every function name.
Objective-C uses an Itanium language-specific data area but gives its type-table
slots Apple runtime semantics. A class catch names an objc_typeinfo, @catch (id) names OBJC_EHTYPE_id, and @catch (...) is the null catch-all entry.
The product line fixes that interpretation to Apple's non-fragile runtime and
crosses it with both Mach-O architectures produced by the pinned Xcode:
| Runtime | Target | Unwind metadata | Personality | Runner | Executables run? |
|---|---|---|---|---|---|
| Apple | arm64-apple-darwin |
__unwind_info + __eh_frame + __gcc_except_tab |
__objc_personality_v0 |
macos-15 |
yes |
| Apple | x86_64-apple-darwin |
__unwind_info + __gcc_except_tab |
__objc_personality_v0 |
macos-15 |
cross-built |
Each cell builds six executables, for a canonical total of 12 artifacts: the
ARC exception probe at -O0 and -O2, each with and without local symbols; an
-O2 manual-retain/release control; and an -O2 -fno-objc-exceptions control.
All six arm64 executables must print objc-eh probe passed before their
fragment can be uploaded. The x86_64 cell is never reported as run.
The architecture-specific __eh_frame contract is measured rather than
assumed. Under the pinned Apple clang 17/Xcode 16.4 line, arm64 keeps a
well-formed DWARF frame chain beside compact unwind, while x86_64 encodes these
frames entirely in __unwind_info. The verifier requires the arm64 chain and
rejects an x86_64 chain, and independently walks the compact-unwind table for
both.
sources/objc-eh/objc_eh_probe.m defines a local NSException subclass and
covers class, framework-class, id, and ellipsis catches; a multi-clause catch
ladder; nested tries; @finally; rethrow; cleanup-only frames;
@synchronized; @autoreleasepool; and an ARC strong local held across a
throwing call. Every probe is externally visible and noinline so the symbol
inventory and exception shapes survive optimization.
The MRR variant changes only -fobjc-arc to -fno-objc-arc. Its binary must
lack the ARC return-value handshake import that both ARC optimization levels
and the exception-free ARC control retain. The exception-free variant changes
only -fobjc-exceptions to -fno-objc-exceptions; it must lack
__gcc_except_tab, __objc_personality_v0, and objc_exception_throw, while
still carrying valid unwind metadata.
Mach-O adds an underscore to C symbols in its raw nlist. Manifests deliberately
use source spellings such as objc_exception_throw and
__objc_personality_v0; object_readers.py exposes that normalized spelling
while retaining the raw name too. This keeps container syntax out of the
Objective-C ABI contract.
Both the directory and filename repeat every build axis:
corpus/objc-eh/apple/arm64-apple-darwin/o2/stripped/
objc_eh_probe-apple-arm64-apple-darwin-o2-stripped
corpus/objc-eh/apple/x86_64-apple-darwin/o2/symtab/
objc_eh_probe_mrr-apple-x86_64-apple-darwin-o2-symtab
The executables have no extension, so .gitattributes marks only the generated
artifact depth as binary and leaves corpus/objc-eh/README.md diffable.
Ada and D reuse the Itanium call-site/action/type-table container, but their
type-table slots are not C++ std::type_info. GNAT stores Exception_Id
descriptors; DMD, GDC, and LDC store ClassInfo descriptors. The producer
therefore records three independent claims and refuses to treat personality
recognition as complete support:
| Claim | What it means |
|---|---|
| parseable LSDA | .eh_frame plus .gcc_except_table decode into a call-site graph |
| native reconstruction | the language personality is preserved and type-table slots stay address-valued opaque descriptors |
| corpus-proven | a real GNAT, GDC, DMD, or LDC artifact exists for that claim |
The matrix is six (toolchain, target) cells, each at -O0 and -O2, for a
canonical total of 12 ELF executables:
| Toolchain | Target | Personality | Descriptor ABI | Runner | Executables run? |
|---|---|---|---|---|---|
| gnat-13 | x86_64-linux-gnu |
__gnat_personality_v0 |
gnat-exception-id |
ubuntu-24.04 |
yes |
| gnat-13 | aarch64-linux-gnu |
__gnat_personality_v0 |
gnat-exception-id |
ubuntu-24.04 |
cross-built |
| gdc-13 | x86_64-linux-gnu |
__gdc_personality_v0 |
d-classinfo |
ubuntu-24.04 |
yes |
| gdc-13 | aarch64-linux-gnu |
__gdc_personality_v0 |
d-classinfo |
ubuntu-24.04 |
cross-built |
| dmd-2.112.1 | x86_64-linux-gnu |
__dmd_personality_v0 |
d-classinfo |
ubuntu-24.04 |
yes |
| ldc-1.42.0 | x86_64-linux-gnu |
_d_eh_personality |
d-classinfo |
ubuntu-24.04 |
yes |
GNAT and GDC install from versioned apt packages. DMD and LDC install from a
pinned dlang-community/setup-dlang revision. GCC-family cells pass
-ffile-prefix-map and -g0; DMD and LDC compile a relative source path
without debug info. The verifier fails if the checkout path is still findable
in a published binary.
Two sources under sources/ada-d-eh/:
ada_eh_probe.adbraisesConstraint_Errorplus two user exceptions, catches each by name, and has anothershandler.d_eh_probe.dthrows threeExceptionsubclasses, catches each by class, has aThrowablefallback, and usesscope (exit)so the D cells must produce a cleanup pad.
Both print ada-d-eh probe passed on the default success path. Native cells
must print that marker before their fragment can be uploaded.
Both the directory and the filename repeat every build axis:
corpus/ada-d-eh/ada/gnat/x86_64-linux-gnu/o2/
ada_eh_probe-gnat-x86_64-linux-gnu-o2
corpus/ada-d-eh/d/ldc/x86_64-linux-gnu/o0/
d_eh_probe-ldc-x86_64-linux-gnu-o0
.github/workflows/ Build, assemble, and publish workflows
corpus/windows-eh/ Committed generated PE files
corpus/rust-eh/ Committed generated ELF, PE, and Mach-O files
corpus/cxx-itanium-eh/ Committed generated ELF, Mach-O, and PE files
corpus/objc-eh/ Committed generated Mach-O files
corpus/ada-d-eh/ Committed generated Ada and D ELF files
manifests/ Canonical machine-readable contracts
schema/ Manifest schemas
scripts/ Matrices, builders, mergers, verifiers, and tests
sources/msvc-exceptions/ Focused ABI probes
sources/rust-eh/ Rust panic and unwinding probes
sources/cxx-itanium-eh/ C++ and C Itanium exception probes
sources/objc-eh/ Objective-C runtime and exception probe
sources/ada-d-eh/ Ada and D Itanium exception probes
sources/windows-seh-tests Pinned official source snapshot
rust-toolchain.toml The exact rustc release the Rust corpus is built with
LICENSES/ Third-party license notices
Cross-platform checks:
python3 -m unittest discover -s scripts/tests -v
python3 -m py_compile \
scripts/windows_matrix.py \
scripts/verify_windows_corpus.py \
scripts/Merge-WindowsCorpus.py \
scripts/rust_matrix.py \
scripts/object_readers.py \
scripts/json_schema_check.py \
scripts/verify_rust_corpus.py \
scripts/merge_rust_corpus.py \
scripts/build_rust_corpus.py \
scripts/cxx_itanium_matrix.py \
scripts/verify_cxx_itanium_corpus.py \
scripts/merge_cxx_itanium_corpus.py \
scripts/build_cxx_itanium_corpus.py \
scripts/objc_matrix.py \
scripts/verify_objc_corpus.py \
scripts/merge_objc_corpus.py \
scripts/build_objc_corpus.py \
scripts/ada_d_eh_matrix.py \
scripts/verify_ada_d_eh_corpus.py \
scripts/merge_ada_d_eh_corpus.py \
scripts/build_language_eh_corpus.py
python3 -m json.tool schema/windows-eh-manifest.schema.json >/dev/null
python3 -m json.tool schema/rust-eh-manifest.schema.json >/dev/null
python3 -m json.tool schema/cxx-itanium-eh-manifest.schema.json >/dev/null
python3 -m json.tool schema/objc-eh-manifest.schema.json >/dev/null
python3 -m json.tool schema/ada-d-eh-manifest.schema.json >/dev/null
python3 scripts/windows_matrix.py --json
python3 scripts/rust_matrix.py --json
python3 scripts/cxx_itanium_matrix.py --json
python3 scripts/objc_matrix.py --json
python3 scripts/ada_d_eh_matrix.py --jsonOn Windows with the required Visual Studio target tools and LLVM components, one Windows cell can be built with PowerShell 7:
./scripts/Build-WindowsCorpus.ps1 `
-Toolchain msvc `
-Architecture x86_64 `
-Optimization o0 `
-SecurityCookie off `
-CxxFormat fh3 `
-OutputRoot ./stagingpython3 scripts/verify_windows_corpus.py \
manifests/windows-eh.json \
--root . \
--require-complete-matrixOne Rust cell can be built anywhere the pinned toolchain and the cell's linker are available:
python3 scripts/build_rust_corpus.py \
--target aarch64-apple-darwin \
--panic-strategy unwind \
--optimization o2 \
--output-root ./staging--describe-only resolves the same cell without building anything, which is how
the producer tests check all 20 cells on a machine with no Rust installed.
python3 scripts/verify_rust_corpus.py \
manifests/rust-eh.json \
--root . \
--require-complete-matrixOne C++ Itanium cell can be built anywhere the cell's drivers are on PATH and
report the pinned release series:
python3 scripts/build_cxx_itanium_corpus.py \
--toolchain clang \
--target arm64-apple-darwin \
--output-root ./staging--describe-only resolves the same cell without building anything, which is how
the producer tests check all nine cells on a machine with no cross toolchain
installed. scripts/cxx_itanium_matrix.py --plan prints the whole 72-artifact
inventory with the contract each entry carries, and --paths prints just the
canonical paths.
python3 scripts/verify_cxx_itanium_corpus.py \
manifests/cxx-itanium-eh.json \
--root . \
--require-complete-matrixOne Objective-C cell can be built on macOS after selecting the pinned Xcode:
sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer
python3 scripts/build_objc_corpus.py \
--runtime apple \
--target arm64-apple-darwin \
--output-root ./staging--describe-only resolves either target without invoking clang.
scripts/objc_matrix.py --plan prints all 12 contracts, and --paths prints
the canonical inventory.
python3 scripts/verify_objc_corpus.py \
manifests/objc-eh.json \
--root . \
--require-complete-matrixOne Ada or D cell can be built anywhere the cell's compiler is on PATH and
reports the pinned release:
python3 scripts/build_language_eh_corpus.py \
--toolchain gnat \
--target x86_64-linux-gnu \
--output-root ./staging--describe-only resolves the same cell without a compiler.
scripts/ada_d_eh_matrix.py --plan prints all 12 contracts.
python3 scripts/verify_ada_d_eh_corpus.py \
manifests/ada-d-eh.json \
--root . \
--require-complete-matrixBuild and publish Windows EH corpus, Build and publish Rust EH corpus, Build and publish C++ Itanium EH corpus, Build and publish Objective-C EH corpus, and Build and publish Ada/D EH corpus each run their complete matrix when their producer source, schema, scripts, or workflow changes. They are independent, and each publishes only its own tree.
- Pull requests build and validate with read-only repository permissions.
- A successful producer change on
mainassembles and re-verifies the complete corpus, then a dedicated job receivescontents: write. - Each publish job synchronizes only its own generated files:
corpus/windows-ehandmanifests/windows-eh.json,corpus/rust-ehandmanifests/rust-eh.json,corpus/cxx-itanium-ehandmanifests/cxx-itanium-eh.json,corpus/objc-ehandmanifests/objc-eh.json, orcorpus/ada-d-ehandmanifests/ada-d-eh.json. Each creates a bot commit only when its own files changed, and pushes it tomain. - Generated-only paths do not trigger any producer workflow, and each workflow's
path filters name its own files rather than
scripts/**, so one line's change does not rebuild another's matrix. Concurrency and trigger-revision checks prevent an older run from publishing over newer producer source.
Repository settings must allow GitHub Actions to write contents and must permit
this generated-file bot commit on main.
An empty remote cannot run a workflow it does not contain. The first publication therefore has this order:
- Review the source snapshots, probes, scripts, schemas, workflows, and docs.
- The repository owner makes the first source/workflow commit and pushes it to
main. - Each workflow builds and pushes its first generated corpus commit.
- NeverD records that reviewed
testbinscommit as its submodule gitlink.
The intended NeverD location is unittests/corpus:
git submodule add \
https://github.com/NeverSight/testbins.git \
unittests/corpus
git submodule update --init --recursive unittests/corpusAfter the canonical generated commit exists, enable the focused consumer tests:
cmake -S . -B build-corpus \
-DBUILD_TESTING=ON \
-DNEVERD_ENABLE_BINARY_CORPUS_TESTS=ON
cmake --build build-corpus \
--target check-neverd-windows-eh-corpus \
--parallel 4
cmake --build build-corpus \
--target check-neverd-rust-eh-corpus \
--parallel 4
cmake --build build-corpus \
--target check-neverd-cxx-itanium-eh-corpus \
--parallel 4Configuration fails immediately if the pinned submodule revision does not contain the manifest a target consumes. NeverD verifies hashes and parses every image as data through its public loader; it never executes corpus binaries.