I also think "undefined behavior" is a problematic term and we should try to find something clearer.
When I've written documentation that touches on these issues for C, I find it works best to talk in terms of assumptions made by different parts of the implementation. Here's a couple of examples.
bool
occupies the same space as au8
, one byte, but the compiler generates code assuming that the numeric value of that byte is always either0
or1
.
The following function [ed.: from this old thread] reads memory beyond the space allocated to the slice
x
. This is incorrect, even ifx
is a subslice of a larger allocation, because the compiler will assume that it does no such thing while generating code for its callers.fn reach_beyond(x: &[i32]) -> i32 { unsafe { *x.as_ptr().add(x.len()+1) } }
A hypothetical Rust language standard would, in these terms, say that "the compiler may assume that (not X)" where the C standard says "the behavior is undefined if (X)".