diff --git a/src/coding-guidelines/attributes/gui_ZDLZzjeOwLSU.rst b/src/coding-guidelines/attributes/gui_ZDLZzjeOwLSU.rst new file mode 100644 index 000000000..925c6c702 --- /dev/null +++ b/src/coding-guidelines/attributes/gui_ZDLZzjeOwLSU.rst @@ -0,0 +1,299 @@ +.. SPDX-License-Identifier: MIT OR Apache-2.0 + SPDX-FileCopyrightText: The Coding Guidelines Subcommittee Contributors + +.. default-domain:: coding-guidelines + +Assure visibility of ``unsafe`` keyword in unsafe code +====================================================== + +.. guideline:: Assure visibility of ``unsafe`` keyword in unsafe code + :id: gui_ZDLZzjeOwLSU + :category: required + :status: draft + :release: 1.85-latest + :fls: fls_8kqo952gjhaf + :decidability: decidable + :scope: crate + :tags: readability, reduce-human-error + + Mark all code that may violate safety guarantees with a visible ``unsafe`` keyword + :cite:`gui_ZDLZzjeOwLSU:RUST-REF-UNSAFE-KEYWORD`. + + The following constructs require explicit ``unsafe`` visibility: + + * ``extern`` blocks must be declared as ``unsafe extern`` + * The ``#[no_mangle]`` attribute must be written as ``#[unsafe(no_mangle)]`` + * The ``#[export_name]`` attribute must be written as ``#[unsafe(export_name)]`` + * The ``#[link_section]`` attribute must be written as ``#[unsafe(link_section)]`` + + .. note:: + + Starting with Rust Edition 2024, the use of ``unsafe`` is required in these contexts. + The ``#[link]`` and ``#[link_ordinal]`` attributes are implicitly covered by the + ``unsafe extern`` requirement, as they must appear on ``extern`` blocks. + See rust-lang/rust#82499 for the tracking issue on unsafe attributes. + + .. rationale:: + :id: rat_eQV3s9ggNegr + :status: draft + + * Auditability and review + + * ``unsafe`` blocks create clear audit boundaries where reviewers can focus on code + that may violate Rust's safety guarantees :cite:`gui_ZDLZzjeOwLSU:RUSTNOMICON-MEET-SAFE` + * Safety-critical standards like ISO 26262 :cite:`gui_ZDLZzjeOwLSU:ISO-26262` and + DO-178C :cite:`gui_ZDLZzjeOwLSU:DO-178C` require traceability of hazardous operations + * Helps enumerate and document all places where safety requirements must be manually upheld + * Satisfies ISO 26262 Part 6, Table 1, objective 1c (use of language subsets) + * Satisfies DO-178C Section 6.3.4.f (source code traceability) + + * Explicit acknowledgment of responsibility + + * The ``unsafe`` keyword signals that the programmer is taking responsibility for + upholding invariants the compiler cannot verify + * Prevents accidental use of ``unsafe`` operations without conscious decision + * Aligns with the principle of defense in depth in safety-critical systems + + * Static analysis and tooling + + * Tools like ``cargo-geiger`` :cite:`gui_ZDLZzjeOwLSU:CARGO-GEIGER`, ``unsafe-inspect``, + and custom linters can automatically locate and count unsafe blocks + * Enables metrics like "unsafe density" for safety assessments + * Supports qualification evidence required by certification standards + + * Traceability for certification + + * Safety-critical certifications require demonstrating that hazardous operations are + identified and controlled + * Visible ``unsafe`` tokens provide direct linkage to safety cases and hazard analyses + * Facilitates the required documentation that each unsafe operation has been reviewed + and justified + + .. non_compliant_example:: + :id: non_compl_ex_FdmuPXGZr4EP + :status: draft + + The ``#[no_mangle]`` attribute is unsafe because it can be used to declare a function + identifier that conflicts with an existing symbol. This noncompliant example declares an + unmangled function named ``convert`` that is missing the required unsafe wrapper in Rust 2024. + + This noncompliant example requires Rust Edition 2021 or earlier to compile. + In Rust Edition 2024, missing ``unsafe`` wrappers cause compilation errors. + + .. rust-example:: + :compile_fail: + :edition: 2024 + + // Undefined behavior by the linker or loader is possible + // if another 'convert' function is defined. + #[no_mangle] + fn convert() {} + + fn main() { + convert(); + } + + .. compliant_example:: + :id: compl_ex_wR1FEyLRKmrr + :status: draft + + Rust Edition 2024 enforces that the ``no_mangle`` attribute requires an ``unsafe`` keyword, + as shown in this compliant example. + + NOTE: This code can still have undefined behavior if the ``convert`` function symbol is + defined more than once. + + .. rust-example:: + :miri: skip + :edition: 2024 + + #[unsafe(no_mangle)] // compliant + fn convert() {} + + fn main() { + convert(); + } + + .. non_compliant_example:: + :id: non_compl_ex_FdmuPXGZr4EO + :status: draft + + This noncompliant example misdeclares the ``malloc`` function in an ``extern "C"`` block + by specifying the type of the ``size`` parameter as ``f32`` instead of ``usize``. + + An ``extern`` block is unsafe because undefined behavior can occur if types or functions are + misdeclared. This is true even if the declarations are not used. This noncompliant example + requires Rust Edition 2021 or earlier to compile. + + .. rust-example:: + :compile_fail: + :edition: 2024 + + use std::ffi; + + extern "C" { + // If 'malloc' is otherwise defined with a 'usize' argument, the compiler + // may generate code for calls to this function using this incompatible declaration, + // resulting in undefined behavior. + fn malloc(size: f32) -> *mut ffi::c_void; + } + + fn main() {} + + .. compliant_example:: + :id: compl_ex_wR1FEyLRKmrq + :status: draft + + Rust Edition 2024 enforces that ``extern "C"`` blocks require an ``unsafe`` keyword, + as shown in this compliant example. + + NOTE: This code can still have undefined behavior if the declared ``malloc`` function is + incompatible with the actual definition. To eliminate this undefined behavior, the + declaration for ``malloc`` used in this compliant example accepts one argument of type ``usize``. + + .. rust-example:: + :miri: skip + :edition: 2024 + + use std::ffi; + + unsafe extern "C" { + // Here the assumption is that malloc is the one defined by C's stdlib.h + // and that size_of::() == size_of::() + fn malloc(size: usize) -> *mut ffi::c_void; + fn free(ptr: *mut ffi::c_void); + } + + fn main() { + unsafe { + let ptr = malloc(1024); + if !ptr.is_null() { + free(ptr); + } + } + } + + .. non_compliant_example:: + :id: non_compl_ex_Hk3mNp5qRs7t + :status: draft + + The ``#[export_name]`` and ``#[link_section]`` attributes can cause undefined behavior if + misused, as they affect symbol resolution and memory layout at link time. Without the + ``unsafe`` keyword, these hazards are not visible to reviewers or tools. + + This noncompliant example has two separate problems. First, it uses an ``#[export_name]`` + attribute without an unsafe wrapper. This attribute controls the symbol name used during + linking. If another symbol with the same name exists, it causes undefined behavior. + Rust 2024 requires it to be marked ``unsafe``. + + The second problem is that this noncompliant example uses a ``#[link_section]`` attribute + without an unsafe wrapper. This attribute places the item in a specific linker section. + Incorrect section placement can cause undefined behavior (e.g., placing mutable data in + read-only sections, or interfering with special sections like ``.init``). + + This noncompliant example requires Rust Edition 2021 or earlier to compile. + + .. rust-example:: + :compile_fail: + :edition: 2024 + + // Collides with the C library 'printf' function + #[export_name = "printf"] // noncompliant + + // Missing unsafe marker - noncompliant in Rust 2024 + #[link_section = ".init_array"] // noncompliant + static DATA: u32 = 42; // Corrupts initialization table! + + fn main() { + println!("DATA = {DATA}"); + } + + .. compliant_example:: + :id: compl_ex_xY2zAb3cDe4f + :status: draft + + The ``#[export_name]`` and ``#[link_section]`` attributes must use the ``unsafe()`` wrapper + to make their safety implications visible. + + .. rust-example:: + :miri: skip + :edition: 2024 + + // SAFETY: 'custom_symbol' does not conflict with any other symbol + #[unsafe(export_name = "custom_symbol")] + pub fn my_function() {} + + // SAFETY: Placing data in a specific section for embedded systems + #[unsafe(link_section = ".noinit")] + static mut PERSISTENT_DATA: [u8; 256] = [0; 256]; + + // SAFETY: Custom section for shared memory + #[unsafe(link_section = ".shared")] + static SHARED_BUFFER: [u8; 4096] = [0; 4096]; + + fn main() { + my_function(); + println!("shared buffer size = {}", SHARED_BUFFER.len()); + unsafe { let _ = PERSISTENT_DATA[0]; } + } + + **Enforcement** + This guideline can be enforced through the following mechanisms: + + * **Rust Edition 2024**: Migrating to Rust Edition 2024 makes violations of this guideline + compilation errors for ``extern`` blocks and unsafe attributes. + + * **Compiler Lints**: Enable the following lints: + + * ``#![deny(unsafe_code)]`` - Denies all unsafe code (use ``#[allow(unsafe_code)]`` for justified exceptions) + * ``#![deny(unsafe_op_in_unsafe_fn)]`` - Requires explicit unsafe blocks within unsafe functions + * ``#![warn(unsafe_attr_outside_unsafe)]`` - Warns about unsafe attributes without the ``unsafe()`` wrapper (pre-2024) + + * **Static Analysis Tools**: + + * ``cargo-geiger`` - Counts and reports unsafe code usage + * ``cargo-audit`` - Checks for known vulnerabilities in dependencies + * Custom Clippy lints for project-specific requirements + + * **Code Review**: Manual review of all code containing ``unsafe`` tokens should be + part of the development process, with documented justification for each usage. + + **Related guidelines** + * Minimize the scope of unsafe blocks + * Document safety invariants for all unsafe code with ``// SAFETY:`` comments + * Prefer safe abstractions over raw unsafe code + * Use ``#![forbid(unsafe_code)]`` at crate level where possible, with explicit exceptions + + .. bibliography:: + :id: bib_n8YJHvQf4mWx + :status: draft + + .. list-table:: + :header-rows: 0 + :widths: auto + :class: bibliography-table + + * - :bibentry:`gui_ZDLZzjeOwLSU:RUST-EDITION-GUIDE` + - The Rust Edition Guide. "Rust 2024." https://doc.rust-lang.org/edition-guide/rust-2024/index.html. + * - :bibentry:`gui_ZDLZzjeOwLSU:RUST-REF-UNSAFE-KEYWORD` + - The Rust Reference. "Unsafe Keyword." https://doc.rust-lang.org/reference/unsafe-keyword.html. + * - :bibentry:`gui_ZDLZzjeOwLSU:RUST-LINT-UNSAFE` + - Rust Compiler Lint Documentation. "unsafe_code." https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#unsafe-code. + * - :bibentry:`gui_ZDLZzjeOwLSU:RUSTNOMICON-MEET-SAFE` + - The Rustonomicon. "Meet Safe and Unsafe." https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html. + * - :bibentry:`gui_ZDLZzjeOwLSU:ISO-26262` + - International Organization for Standardization. "ISO 26262 - Road vehicles - Functional safety." https://www.iso.org/standard/68383.html. + * - :bibentry:`gui_ZDLZzjeOwLSU:DO-178C` + - RTCA, Inc. "DO-178C: Software Considerations in Airborne Systems and Equipment Certification." https://store.accuristech.com/standards/rtca-do-178c. + * - :bibentry:`gui_ZDLZzjeOwLSU:CARGO-GEIGER` + - cargo-geiger contributors. "cargo-geiger: Detects usage of unsafe Rust." https://github.com/geiger-rs/cargo-geiger. + * - :bibentry:`gui_ZDLZzjeOwLSU:RUST-REF-EXTERN` + - The Rust Reference. "External blocks." https://doc.rust-lang.org/reference/items/external-blocks.html. + * - :bibentry:`gui_ZDLZzjeOwLSU:RUST-REF-UNSAFE-ATTR` + - The Rust Reference. "Unsafe attributes." https://doc.rust-lang.org/reference/attributes.html#unsafe-attributes. + * - :bibentry:`gui_ZDLZzjeOwLSU:FERROCENE-SPEC` + - Ferrocene GmbH. "Ferrocene Language Specification." https://spec.ferrocene.dev/. + * - :bibentry:`gui_ZDLZzjeOwLSU:RUST-REF-UNION` + - The Rust Reference. "Unions." https://doc.rust-lang.org/reference/items/unions.html. + * - :bibentry:`gui_ZDLZzjeOwLSU:UCG-VALIDITY` + - Rust Unsafe Code Guidelines. "Validity and Safety Invariant." https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#validity-and-safety-invariant. diff --git a/src/coding-guidelines/attributes/index.rst b/src/coding-guidelines/attributes/index.rst index f952c3d4b..9f5608b9c 100644 --- a/src/coding-guidelines/attributes/index.rst +++ b/src/coding-guidelines/attributes/index.rst @@ -5,3 +5,10 @@ Attributes ========== + +.. toctree:: + :maxdepth: 1 + :titlesonly: + :glob: + + gui_*