-
Notifications
You must be signed in to change notification settings - Fork 28
Description
This file contains more suggestions for guidelines. Please indicate which ones you would like to see turned into rules and which ones not so much. Please provide your rationale and identify any concerns you have (even for rules you would like to see adopted).
- Do not depend on function pointer identity across crates
Guideline: Avoid comparing function pointers (fn() values) for equality when the functions originate from different crates or may be inlined across crate boundaries.
Rationale: Cross-crate inlining, LTO, and codegen-unit splitting may cause logically identical functions to have distinct compiled addresses, breaking equality checks.
- Treat vtable pointer identity as unstable
Guideline: Do not rely on the address or identity of a trait object’s vtable for correctness, including through pointer comparison or hashing.
Rationale: Vtable instantiation is a compiler implementation detail. Different crates, codegen-units, or optimization levels may generate distinct vtables with identical semantics.
- Avoid using pointer equality as a logical predicate
Guideline: Do not rely on raw pointer equality (ptr1 == ptr2) to determine logical equality or uniqueness of data unless the pointers originate from the same allocation and the relationship is explicitly guaranteed.
Rationale: Distinct allocations may contain identical data. Cross-crate LTO and inlining can also move or duplicate code or data, making address comparisons brittle.
- Never assume stable symbol addresses across crates
Guideline: Treat symbol addresses (including &STATIC, fn pointers, and vtable addresses) as non-stable across crates and builds. Avoid designs that depend on global identity properties of these symbols.
Rationale: Different compiler settings, incremental build states, or LTO passes may change symbol instantiation and placement.
- Do not assume stable struct layout across crates without #[repr(...)]
Guideline: Any type expected to be shared or transmuted across crate boundaries must have an explicit representation attribute (#[repr(C)] or equivalent).
Rationale: Rust’s default layout is unspecified and may differ between crates or compiler versions. This affects FFI, transmutation, DMA/packed buffers, and memory-mapped I/O.
- Avoid using mem::transmute or pointer casts across crates unless representation is fully specified
Guideline: Conversions that reinterpret memory (via mem::transmute, pointer::cast, or reading raw bytes into structs) must only target types whose size, alignment, and layout invariants are explicitly defined and documented.
Rationale: Layout is not stable across crates or optimizer settings unless representation is fixed.
- Do not depend on compiler optimizations when encoding program invariants
Guideline: Program correctness must not rely on specific optimizer behavior (e.g. inlining, dead-code elimination, codegen-unit merging). Invariants must hold independent of optimization level and backend.
Rationale: Optimizers may generate different control flow, merge or duplicate functions, or eliminate expected side effects.
- Keep identity-sensitive logic within a single crate
Guideline: If a design requires function identity, static identity, or address-based deduplication, the logic must be confined to a single crate or protected with #[inline(never)] and explicit documentation.
Rationale: Within a crate (and with inlining prevented), identity semantics are much more stable and predictable.
- Avoid cross-crate unsafe abstractions that require stable metadata
Guideline: Unsafe abstractions must not rely on metadata that can vary between crates (vtable pointers, symbol addresses, layout padding, etc.). Unsafe APIs should enforce all invariants at boundaries.
Rationale: Safe code in a dependent crate may unknowingly break the assumptions of unsafe code unless invariants are fully encapsulated.
- Validate behavior under multiple build profiles
Guideline: For any code relying on layout guarantees, identity semantics, pointer stability, or trait object behavior, test across:
debug vs release,
LTO vs non-LTO,
different codegen-unit counts,
incremental vs non-incremental builds.
Rationale: Subtle identity- or layout-related bugs may appear only under certain compilation profiles (as seen in #117047). Safety-critical systems should proactively detect these divergences.