Pitfalls of Safe Rust

Casting and the as Operator

  • Many see as (especially for narrowing integer conversions) as a remaining “footgun” in otherwise safety‑oriented Rust.
  • Desired alternatives:
    • Convenient checked casts (try_into-style, but with lighter syntax),
    • Separate, visually loud syntax for lossy/modulo casts.
  • Others argue as is pragmatically necessary, especially for deliberate truncation, and that the real issue is making safe conversions less verbose.
  • There is mention of lints and a slow push to de‑emphasize as, but some conversions (e.g., integer→float) still lack clear safe APIs.

Overflow and Numeric Correctness

  • Strong disagreement over how serious integer overflow is:
    • Some claim overflows are rare and not worth pervasive checked arithmetic.
    • Others, citing formal verification experience, say overflows are extremely common bugs and often security‑relevant.
  • Rust’s choice: checks in debug builds, explicit APIs (checked_*, saturating_*, Wrapping, Saturating types) for release.
  • Debate over defaults: some want checked arithmetic and panics by default in release; others prioritize performance and point to compiler flags for enabling checks.
  • Refinement/liquid types (e.g., Flux) are discussed as a promising direction to statically rule out overflows and out‑of‑bounds accesses.

What “Safe Rust” Means

  • One camp: “safe Rust” is specifically “memory‑safe Rust” (no UB from safe code), matching official docs and the unsafe keyword.
  • Another camp informally broadens “safe” to “if it compiles, it probably works,” bundling memory safety with stronger typing and APIs.
  • This mismatch fuels confusion and accusations of “false advertising,” especially when contrasted with C++.

Rust vs C++, Go, and Others

  • Several comments compare Rust’s guarantees with C++:
    • C++ smart pointers/containers help, but UB remains easy (null deref, unchecked operator[], iterator invalidation, optional/variant misuse).
    • Rust’s borrow checker, Option, and trait system make many C++-style bugs impossible or much harder.
  • Go is suggested by some as better for robust services; others counter that Go lacks null safety and Rust’s strong typing, and Rust can more systematically prevent data races.

Other Pitfalls and APIs

  • Path handling: Path::join discarding the prefix when given an absolute path is seen as a footgun; some want a distinct “prefix if relative” API.
  • Memory leaks via Rc/Arc cycles are noted, but others argue they’re relatively hard to create accidentally due to ownership, immutability, and type structure.
  • Misuse of mem::size_of_val(&T) (measuring the reference, not the pointee) is flagged as a subtle but serious trap in low‑level code.