- use after free
- breaking the aliasing rules
- causing a "data race" (e.g. writing to the same value from multiple threads without a lock)
- producing an invalid value (like a bool that's not 0 or 1)
There's some other technical stuff like "calling a foreign function with the wrong ABI", but those four above capture most of what safe Rust wants to guarantee that you never do. I contrast, the same page provides an interesting list of things that Rust doesn't consider UB and that you can do in safe code, for example:
- deadlocks and other race conditions that aren't data races
- leak memory
- overflow an integer
- abort the whole process