3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-08-02 20:23:27 +00:00
Commit graph

1 commit

Author SHA1 Message Date
Copilot
a3be01b9ca
Fix releaseClang segfault: declare invoke_exit_action [[noreturn]], remove __builtin_unreachable() from UNREACHABLE() (#10295)
Commit d46fbad3 added `__builtin_unreachable()` to the `UNREACHABLE()`
macro in Clang builds to suppress `-Wimplicit-fallthrough` warnings. In
Release+Clang mode, this causes UB: Clang can legally eliminate the
`invoke_exit_action` call (since reaching `__builtin_unreachable()` is
UB, the compiler assumes the entire branch is dead), so when
`UNREACHABLE()` is actually hit, the function continues with
uninitialized state — producing the segfault observed in the FPA C
example.

## Changes

- **`src/util/debug.h`** — Declare `invoke_exit_action` as
`[[noreturn]]`. This is semantically accurate: the function always
terminates via `exit()` or `throw`, never returning normally. The
`[[noreturn]]` annotation naturally suppresses `-Wimplicit-fallthrough`
after `UNREACHABLE()` without any UB.
- **`src/util/debug.h`** — Remove `__compiler_unreachable` macro and its
use in `UNREACHABLE()`. With `[[noreturn]]` on `invoke_exit_action`, it
is redundant.
- **`src/util/debug.cpp`** — Add `[[noreturn]]` to the
`invoke_exit_action` definition to match.

```cpp
// Before (broken in Release+Clang: UB allows optimizer to eliminate invoke_exit_action)
# define UNREACHABLE() { notify_assertion_violation(...); invoke_exit_action(ERR_UNREACHABLE); }; __builtin_unreachable()

// After (invoke_exit_action is [[noreturn]], no UB)
# define UNREACHABLE() { notify_assertion_violation(...); invoke_exit_action(ERR_UNREACHABLE); } ((void) 0)
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-29 13:23:43 -07:00