safety(codegen): debug_assert companion for every unsafe get_unchecked

Pair every codegen-emitted `unsafe { ... get_unchecked ... }` with a
debug_assert! that re-states the safety obligation as a runtime
predicate. Free in release (debug_assert! compiles to nothing); in
dev/test/miri builds, every dispatch through the 68 behavior tests
exercises these checks, so any future regression in the codegen's
invariants trips loudly.

Sites covered:
  - step()'s __DISPATCH lookup        (sync + async)
  - apply_path()'s __PATH_RANGE +
    __PATH_DATA[..] slice ranges      (sync + async)
  - follow_defaults()'s __DEFAULT_CHILD lookup (sync + async)
  - do_terminate()'s __TERMINATE_RANGE +
    __TERMINATE_DATA[..] slice ranges (sync + async)

Verification:
  - cargo nextest: 68/68 pass (debug_assert! active)
  - cargo +nightly miri test: 66/66 pass (UB detector)
  - cargo bench --bench dispatch: zero release-mode regression
    (asserts compile out as expected)
This commit is contained in:
swaits committed 2026-05-04 15:29:24 -06:00
1 parent da1f3046b4
commit b9645f80cb
1 file changed
+13
+13
View File
@@ -2691,6 +2691,11 @@ pub fn generate(ir: &Ir) -> TokenStream {
// values < #n_states. __ev_id was checked != u16::MAX
// and __event_to_id returns < #n_events otherwise.
// Hence __dispatch_idx < #n_dispatch = __DISPATCH.len().
// The debug_assert is the safety obligation
// expressed at runtime in debug builds — every
// hsmc behavior test exercises this site, so a
// codegen invariant break trips it loudly.
debug_assert!(__dispatch_idx < __DISPATCH.len());
let (__handler_state, __actions, __target) = unsafe {
*__DISPATCH.get_unchecked(__dispatch_idx)
};
@@ -2973,7 +2978,9 @@ pub fn generate(ir: &Ir) -> TokenStream {
// The triple (s, m, e) was emitted at codegen with the
// invariant 0 <= s <= m <= e <= __PATH_DATA.len(), so the
// two slice ranges are in-bounds.
debug_assert!(idx < __PATH_RANGE.len());
let (s, m, e) = unsafe { *__PATH_RANGE.get_unchecked(idx) };
debug_assert!((s as usize) <= (m as usize) && (m as usize) <= (e as usize) && (e as usize) <= __PATH_DATA.len());
let exit_path = unsafe {
__PATH_DATA.get_unchecked(s as usize..m as usize)
};
@@ -3107,6 +3114,7 @@ pub fn generate(ir: &Ir) -> TokenStream {
while let Some(cur) = self.current {
// SAFETY: cur is a state id < #n_states (codegen
// invariant — see __DISPATCH lookup safety note).
debug_assert!((cur as usize) < __DEFAULT_CHILD.len());
let target = match unsafe { *__DEFAULT_CHILD.get_unchecked(cur as usize) } {
Some(t) => t,
None => return,
@@ -3128,6 +3136,7 @@ pub fn generate(ir: &Ir) -> TokenStream {
async fn follow_defaults(&mut self) {
while let Some(cur) = self.current {
// SAFETY: see sync branch — same invariant.
debug_assert!((cur as usize) < __DEFAULT_CHILD.len());
let target = match unsafe { *__DEFAULT_CHILD.get_unchecked(cur as usize) } {
Some(t) => t,
None => return,
@@ -3208,7 +3217,9 @@ pub fn generate(ir: &Ir) -> TokenStream {
if let Some(cur) = self.current {
// SAFETY: cur < #n_states (codegen invariant). The
// (s, e) tuple was emitted with 0 <= s <= e <= len.
debug_assert!((cur as usize) < __TERMINATE_RANGE.len());
let (s, e) = unsafe { *__TERMINATE_RANGE.get_unchecked(cur as usize) };
debug_assert!((s as usize) <= (e as usize) && (e as usize) <= __TERMINATE_DATA.len());
let path = unsafe {
__TERMINATE_DATA.get_unchecked(s as usize..e as usize)
};
@@ -3226,7 +3237,9 @@ pub fn generate(ir: &Ir) -> TokenStream {
async fn do_terminate(&mut self) {
if let Some(cur) = self.current {
// SAFETY: see sync branch — same invariant.
debug_assert!((cur as usize) < __TERMINATE_RANGE.len());
let (s, e) = unsafe { *__TERMINATE_RANGE.get_unchecked(cur as usize) };
debug_assert!((s as usize) <= (e as usize) && (e as usize) <= __TERMINATE_DATA.len());
let path = unsafe {
__TERMINATE_DATA.get_unchecked(s as usize..e as usize)
};