Skip to content

test: instantiate the reference specializations in the hardened build - #82

Open
steve-downey wants to merge 1 commit into
bemanproject:mainfrom
steve-downey:hardened-ref-specializations
Open

test: instantiate the reference specializations in the hardened build#82
steve-downey wants to merge 1 commit into
bemanproject:mainfrom
steve-downey:hardened-ref-specializations

Conversation

@steve-downey

Copy link
Copy Markdown
Member

Follow-up to an incidental finding from #80.

expected_hardened.test.cpp only ever used expected<T, E> and expected<void, E> with a value E. Consequently the precondition checks in the expected<T&, E> specialization were never compiled at all, and neither the primary nor the void specialization was ever instantiated with a reference E. Of the 21 BEMAN_EXPECTED_TRAP() sites in the header, only 15 were reachable by any translation unit in the hardened build — the six in expected<T&, E> were dead as far as the test suite was concerned.

Adds happy-path coverage for expected<T&, E>, expected<T, E&>, expected<T&, E&> and expected<void, E&>, in the same style as the existing sections.

What this does and doesn't buy

The checks are the same if (!has_val_) TRAP shape throughout, so this is mostly about compiling them at all — it is fairly boring, and arguably shouldn't be load-bearing. What it does verify beyond mere instantiation is that the guarded bodies still return the right thing once T or E is a reference: the shallow-const observers in particular, where a const expected still hands out a mutable T* / T& / E&, and where const E& with E = int& collapses back to int&. Those are asserted with static_assert alongside the runtime checks.

Happy paths only, matching the rest of the file: a violated precondition traps, and that cannot be observed from inside the process — __builtin_trap() kills it with SIGILL before anything can report.

Verification

Trap sites present in the gcov data for the hardened TU, before and after:

before: 15  [943 952 961 970 979 988 1051 1060 1069 1078 1977 2000 2009 2018 2027]
after:  21  [... 2973 2982 3022 3031 3040 3049]

Hardened target goes from 5 test cases to 13; full suite 1089/1089 green; clang-format clean.

Independent of #80 — no file overlap. Worth noting for whoever merges second: #80 excludes BEMAN_EXPECTED_TRAP() lines from the gcovr report by pattern, and that pattern already matches all 21 sites, so the two compose without adjustment.

🤖 Generated with Claude Code

expected_hardened.test.cpp only ever used expected<T, E> and expected<void, E>
with a value E. Consequently the precondition checks in the expected<T&, E>
specialization were never compiled at all, and neither the primary nor the void
specialization was ever instantiated with a reference E. Of the 21
BEMAN_EXPECTED_TRAP() sites in the header, only 15 were reachable by any
translation unit in the hardened build; the six in expected<T&, E> were dead as
far as the test suite was concerned.

Adds happy-path coverage for expected<T&, E>, expected<T, E&>,
expected<T&, E&> and expected<void, E&>, in the same style as the existing
sections. All 21 trap sites are now compiled.

The checks are the same `if (!has_val_) TRAP` shape throughout, so this is
mostly about compiling them at all. What it does verify beyond that is that the
guarded bodies still return the right thing once T or E is a reference -- the
shallow-const observers in particular, where a const expected still hands out a
mutable T* / T& / E&, and where `const E&` with E = int& collapses back to int&.

Happy paths only, matching the rest of the file: a violated precondition traps,
and that cannot be observed from inside the process.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant