Rust Rule Catalogue#
Rust Coding Rules Catalogue
|
status: draft
security: YES
safety: ASIL_B
|
||||
These are draft rules. The proposed levels take effect only after adoption through the Software Development Plan as described in Rust Coding Rules (MISRA-derived draft). Enforcement candidates require validation under Verification and Deviations; a source mapping does not establish compliance.
SCR-RUST-001: Define the supported Rust language and build configuration#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 4.1.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: All production crates and their build inputs.
Each component shall record its compiler/toolchain revision, the language specification revision used as the reference for that toolchain (for example a Ferrocene Language Specification revision, with relevant known differences noted), Rust edition, target, dependency resolution, enabled features, panic strategy and overflow-check settings. Production builds shall use this controlled configuration. Stable toolchains reject unstable features; where a nightly or custom toolchain is permitted, the assessment shall list the permitted unstable features and the assumptions relied on. Links to the existing configuration and assessment records satisfy this requirement.
Check: Check manifests, lockfiles and Bazel toolchain/configuration in CI; review language and target assumptions against the referenced specification and the compiler documentation.
Coverage limit: A successful build does not establish tool qualification. Reconcile Cargo and Bazel inputs; a host-only build does not cover QNX or a different feature set.
SCR-RUST-002: Enforce selected diagnostics and control suppressions#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 0.0.1 (SCRC draft: safe), 0.2.1 (SCRC draft: safe), 0.2.2 (SCRC draft: safe), 0.2.3 (SCRC draft: safe), 0.2.4 (SCRC draft: safe), 4.1.2 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: All first-party production crates.
The adopted lint profile shall make selected unused-code, unused-value, unreachable-code and deprecated-API diagnostics blocking. Any suppression shall identify a scoped rationale and rule/deviation. Suppressions inherited from generated or third-party code shall be recorded separately.
Check: Candidate rustc lints: dead_code, unused_variables, unused_assignments, unreachable_code, unused_must_use and deprecated. Verify flags actually reach every Bazel and Cargo analysis action.
Coverage limit: Warnings are not hard language guarantees. These diagnostics are partial, especially for semantic unreachability, public APIs and feature-disabled code. Do not equate a warning-free build with complete coverage of the mapped rules.
SCR-RUST-003: Avoid invariant decisions and ineffective writes#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 0.0.2 (SCRC draft: safe), 0.1.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production control flow.
Level rationale: Required although both sources are Advisory: an invariant condition or an ineffective write usually indicates a logic defect, the consequence in Rust is the same as in C++, and compiler and Clippy checks make conformance cheap to demonstrate.
A condition shall express a decision whose outcome can differ at runtime for inputs the component accepts. A condition whose outcome is fixed is a violation whether it is written as a constant expression or fixed by construction, such as testing a value just assigned from a literal or comparing a value with itself, unless it is a designated configuration choice (a cfg predicate or a named constant flag) or an intentional loop with an explicit exit. A value shall not be written and then overwritten or dropped before any observation. This covers both assignments overwritten before being read and owning values replaced before being observed (adaptation of 0.1.1 to all Rust objects, not only trivially destructible ones). Replacing an owning value runs its Drop, so such a write is unnecessary only when neither the value nor its destructor effect is required.
Check: rustc unused_assignments; selected Clippy condition/comparison checks; candidate CodeQL control-flow and value-use analysis; review intentional constant branches.
Coverage limit: Local diagnostics do not establish path feasibility or detect every overwritten value across calls, and unused_assignments does not consider destructor effects. Record intentional loop and configuration exceptions.
Example:
// Compliant: the outcome depends on runtime input.
fn accept(frame: &[u8]) -> Result<(), ()> {
if frame.len() > MAX_FRAME { return Err(()); }
Ok(())
}
// Non-compliant: the condition is fixed by construction.
fn accept(frame: &[u8]) -> Result<(), ()> {
let ready = true;
if ready { return Ok(()); }
Err(())
}
Both compile. The first decides on the accepted input; the second always takes the first branch, so
the else path is dead and the decision is meaningless unless ready is a documented configuration
flag.
SCR-RUST-004: Handle results and preserve error information#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 0.1.2 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production APIs and their callers.
Non-unit results of explicit function and method calls shall be used or deliberately discarded under
the project’s reviewed discard convention, for example a let _ = binding with a comment naming
why the value is not needed (adaptation of 0.1.2, which covers explicit call syntax and not operator
syntax). #[must_use] contracts apply in addition, including to functions returning unit. Errors
shall be propagated, converted with necessary context, or handled according to the API’s documented
error-handling contract. A Result is critical when that contract states that the error requires
action by the caller; discarding a critical error through let _, drop, .ok(), a default
value or a catch-all branch is prohibited unless the branch implements the documented recovery.
Project APIs shall carry #[must_use] where omission is a defect and shall document which errors
require action and what handling is acceptable.
Check: rustc unused_must_use and selectively unused_results; Clippy let_underscore_must_use; candidate CodeQL checks for project error-discard patterns; review recovery paths.
Coverage limit: #[must_use] checks that a result is used, not that it is handled
meaningfully. Whether .ok() or a catch-all branch discards or recovers rests on the API
contract, which no lint can judge; broad unused_results can flag intentional side-effect APIs.
SCR-RUST-005: Define floating-point range and precision contracts#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 0.3.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Floating-point calculations, conversions and persistence.
Level rationale: Required although Directive 0.3.1 is Advisory: unspecified floating-point range, precision or special-value handling produces silent numerical error in stored and compared values, which is a safety consequence rather than a style concern.
Safety-relevant floating-point calculations shall be covered by a numerical contract that specifies acceptable range, precision, rounding, comparison tolerance, handling of NaN, infinity and signed zero, and serialization guarantees. One shared contract may cover all calculations it applies to, for example at a module or API boundary, provided each calculation is traceable to it. Serialization shall preserve the required information or reject values that cannot meet the contract.
Check: Selected Clippy floating-point/cast checks; boundary and round-trip tests; numerical review. Candidate CodeQL checks can locate values reaching sensitive conversion APIs.
Coverage limit: A lint cannot select application tolerances or prove numerical accuracy. Components that store integers as f64 (for example in a JSON backend) need an explicit round-trip contract.
SCR-RUST-006: Validate preconditions at trust boundaries#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 0.3.2 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Public APIs, external data, stored data and unsafe wrappers.
A function shall be called only when its documented preconditions hold. Encode invariants in validated types where possible; otherwise validate untrusted values before use and return a defined error. Stored data shall be treated as potentially malformed.
Check: Type/API review and negative tests; candidate CodeQL source-to-use checks with explicitly modeled validators and error paths.
Coverage limit: A validation call is not sufficient evidence unless the checked property and success branch match the precondition. Arbitrary application contracts require review.
Example:
// Compliant for this input contract: an untrusted rate is valid only in 1..=10.
fn rate(raw: u8) -> Result<u8, ()> {
if (1..=10).contains(&raw) { Ok(raw) } else { Err(()) }
}
// Non-compliant: accepts out-of-range input.
fn rate(raw: u8) -> Result<u8, ()> {
Ok(raw)
}
Both compile. Only the first rejects input outside the documented precondition.
SCR-RUST-007: Isolate unsafe operations and establish their contracts#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 4.1.3 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Unsafe code, unsafe traits/attributes, safe wrappers and their dependencies.
Undefined behavior is prohibited. Unsafe operations shall be confined to identified modules and justified by operation-specific invariants covering validity, lifetime, aliasing, alignment and concurrency as applicable. Safe APIs shall preserve soundness for all permitted safe callers. Crates designated safe-only shall forbid unsafe_code.
Check: rustc unsafe_op_in_unsafe_fn; Clippy missing_safety_doc and undocumented_unsafe_blocks; independent unsafe review; targeted Miri and applicable verification.
Coverage limit: Documentation checks establish presence, not correctness. Miri covers supported executed paths. A crate with no unsafe blocks may still rely on unsafe dependencies; panic freedom is a separate property.
Example:
// Compliant: handles every slice length without unsafe access.
fn first(input: &[u8]) -> Option<u8> {
input.first().copied()
}
// Non-compliant: the safe API permits an invalid read for input = &[].
fn first(input: &[u8]) -> Option<u8> {
Some(unsafe { *input.as_ptr() })
}
Both function bodies compile. An empty slice is a valid input to either safe function; Miri accepts the first and reports undefined behavior for the second on an empty slice. A safe wrapper must be sound for every input its signature admits.
SCR-RUST-009: Remove disabled code from comments#
Proposed level: Advisory. Source IDs (MISRA C++:2023, draft SCRC assessment): 5.7.1 (SCRC draft: safe), 5.7.2 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production source comments.
Level rationale: Advisory although Rule 5.7.1 is Required: text matching cannot reliably separate disabled code from documentation, so enforcement rests on review judgement. The nested block comment hazard from 5.7.1 is recorded in the requirement.
Obsolete implementations shall be removed and recovered through version control when needed, rather
than parked in comments or behind permanently false or undeclared cfg predicates, the Rust analogue
of #if 0 (adaptation of 5.7.2). Supported feature, target and test configurations are
intentional conditional compilation and are not affected. Nested block comments shall not be used to
disable code, since Rust nests /* */ and a stray delimiter can hide a whole section (concern of
5.7.1); a block comment containing code shall be a documentation example or explanatory pseudocode.
Comments should explain intent and constraints.
Check: Code review; a comment-pattern checker may identify candidates; rustc unexpected_cfgs with check-cfg identifies undeclared predicates used to park code.
Coverage limit: Text matching cannot reliably distinguish obsolete code from useful documentation.
SCR-RUST-010: Make array and buffer extents explicit at interfaces#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): No direct mapping.
Origin: S-CORE supplement (raw buffer extents at foreign interfaces). Scope: Rust APIs and foreign buffer boundaries.
Use arrays or slices that carry the required extent in native Rust interfaces. Raw buffer interfaces shall document pointer, length, ownership and validity together, with validation before constructing a slice.
Check: Compiler typing for native arrays/slices; API review and boundary tests for raw pointer/length pairs.
Coverage limit: Native array extents are largely compiler-enforced. FFI buffer validity is not, and bounds-checked access can still panic.
SCR-RUST-011: Keep imports and module interfaces explicit#
Proposed level: Advisory. Source IDs (MISRA C++:2023, draft SCRC assessment): 19.0.3 (SCRC draft: safe), 19.2.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Crate/module layout and source inclusion.
Level rationale: Advisory although Rule 19.2.1 is Required: Rust’s module system removes the undefined and ambiguous behavior of C++ header inclusion, leaving clarity and provenance of names as the residual concern.
Imports and re-exports should make dependencies and ownership of names clear. Keep ordinary imports
together; document exceptions for narrow local scope. Glob imports should be limited to explicitly
designated preludes or tests. Generated or included source (include!, include_str!, build-
script output, #[path] attributes) shall have controlled provenance: a reviewer can trace it to
a reviewed source file or to a controlled build input recorded in the component’s source and build
records, and generation is reproducible from those inputs. Existing source and build records satisfy
this; include! shall not shadow items of an outer scope (19.2.1).
Check: Formatting, compiler name resolution, selected import lints and review of re- export/prelude design.
Coverage limit: Rust permits include! and generated source; valid syntax alone does not
establish clarity or provenance.
SCR-RUST-012: Reserve entry-point naming#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 6.0.4 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: First-party production functions.
Reserve main for actual executable entry points. Other production functions shall use names expressing their role. Generated wrappers and embedded entry-point conventions require an explicit scoped exception.
Check: A syntax/name checker can enforce the declared policy; review generated and platform entry points.
Coverage limit: This is a project naming restriction, not a Rust language requirement.
Example:
// Compliant: the helper's name describes its role.
mod worker {
pub fn process() -> u8 { 1 }
}
fn main() { let _ = worker::process(); }
// Non-compliant: worker::main is not an executable entry point.
mod worker {
pub fn main() -> u8 { 1 }
}
fn main() { let _ = worker::main(); }
Both compile and run. The nested main violates the naming policy; worker is an ordinary
production module with no generated-wrapper or embedded-entry-point exception.
SCR-RUST-013: Control exported symbols and foreign declarations#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 6.0.3 (SCRC draft: unsafe), 6.2.1 (SCRC draft: unsafe), 6.2.2 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Linkage attributes, exported symbols and foreign bindings.
Exported symbols shall have unique definitions and compatible declarations in each delivered binary.
Centralize foreign declarations in reviewed binding modules/crates. Use minimal visibility; justify
no_mangle, export_name, link_section and equivalent linkage controls. Items exported with
#[no_mangle], #[unsafe(no_mangle)] or export_name enter the global symbol namespace
(6.0.3): each shall be declared in a reviewed binding module and its name shall be unique across the
delivered binary.
Check: Compiler/linker checks, binding review and final symbol-table inspection for each delivered target.
Coverage limit: Cross-crate/linker behavior is not fully captured by Rust name resolution. Edition 2021 permits syntax that edition 2024 marks unsafe; do not scope this check by unsafe blocks alone.
SCR-RUST-014: Avoid misleading name shadowing and method resolution#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 6.4.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Bindings, inherent methods and trait methods.
Rebinding shall not silently change the logical meaning of a value. A same-name binding is permitted
when the new value is the same quantity in a refined form (trimmed, parsed, validated, unwrapped)
and the transformation is visible in the initializer. It is prohibited when the new binding
represents a different quantity, unit or role. Where inherent and trait methods share a name but
differ semantically, use explicit qualification or change the API; this method-resolution policy is
an S-CORE addition without a MISRA C++ source, since the SCRC draft assesses 6.4.2 as not applicable
until supertrait_item_shadowing stabilizes.
Check: Selected Clippy shadowing checks plus type-aware custom checks and review of trait/inherent method collisions.
Coverage limit: This intentionally adapts the C++ restriction to Rust idioms. Rust trait composition is not class inheritance; a broad shadowing ban would enforce a different policy. Clippy shadow lints cannot judge whether a quantity changed meaning.
Example:
// Compliant: same quantity, refined form, transformation visible.
fn parse(input: &str) -> Option<u32> {
let input = input.trim();
input.parse().ok()
}
// Non-compliant: the same name now holds a different unit.
fn schedule(timeout: u32) -> u32 {
let timeout = timeout * 1000; // seconds silently become milliseconds
timeout + 1
}
Both compile. In the first the rebinding is still input, only trimmed. In the second timeout
changes unit under the same name, so later readers cannot tell which unit a use refers to.
SCR-RUST-015: Preserve lifetimes across raw interfaces#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 6.8.1 (SCRC draft: unsafe), 6.8.2 (SCRC draft: unsafe), 6.8.3 (SCRC draft: unsafe), 6.8.4 (SCRC draft: unsafe), 8.1.2 (SCRC draft: unsafe), 28.6.3 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: References, raw pointers, callbacks and ownership transfers.
An access shall not outlive its referent. Do not expose a dangling local pointer as a usable API
result or store borrowed addresses beyond their valid lifetime. Closures and callbacks that capture
raw pointers to local data shall be invoked only while that data is live; if the callback can run
later, the captured storage shall be owned or 'static (8.1.2). Storing or transporting a
dangling raw-pointer value is permitted; accessing its expired referent is not. After a value has
been moved out of or dropped from storage reachable through a raw pointer, a typed read of that
storage requires initialization, validity and ownership to be re-established first; copying a
Copy value leaves the source initialized (28.6.3). Raw-pointer wrappers shall establish lifetime
invariants for returned references and asynchronous/foreign callbacks.
Check: Borrow checking for references; available dangling-pointer diagnostics; unsafe/API review and targeted Miri tests.
Coverage limit: Creating or returning a dangling raw pointer can compile. Compiler-enforced reference lifetimes do not establish equivalent guarantees for raw pointers or foreign callbacks.
SCR-RUST-016: Make numeric, Boolean and character conversions intentional#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 7.0.1 (SCRC draft: safe), 7.0.2 (SCRC draft: unsafe), 8.2.2 (SCRC draft: safe), 10.2.3 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: All conversions, including safe casts and unsafe reinterpretation.
Related draft SCRC guideline: gui_ADHABsmK9FXz (numeric uses of as, for 8.2.2). This rule is to be reconciled with the SCRC text as it matures.
Conversions shall preserve the required value or perform explicit range/validity checks with a
defined error. bool and char shall not be used as incidental numbers: arithmetic on
bool, and casts from char other than the lossless char as u32 or u32::from(c), are
prohibited outside documented encoding or decoding boundaries. At such a boundary a narrowing
character cast such as char as u8 requires a preceding range check or a checked conversion such
as u8::try_from(u32::from(c)). The prohibition of truncating character casts is an S-CORE
addition; the SCRC draft assesses 7.0.3 as not applicable. Lossy floating-point conversion requires
a precision contract.
Check: Clippy cast_possible_truncation, cast_possible_wrap, cast_sign_loss, cast_precision_loss and cast_lossless as candidate mappings; custom conversion inventory and boundary tests.
Coverage limit: as is legal in safe Rust, so an inventory is needed. From/TryFrom
are preferred where supplied, but not every numeric pair implements them. The encoding-boundary
exception and the character-cast restriction are S-CORE adaptations, not verbatim MISRA
requirements.
SCR-RUST-017: Represent absent pointers explicitly#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): No direct mapping.
Origin: S-CORE adaptation of the C++ null-pointer-constant concern; MISRA C++ 7.11.1 is assessed not applicable and is not retained as a source. Scope: Raw-pointer and foreign APIs.
Use typed null constructors when a raw null pointer is required. Use Option or another explicit type for optional references/handles in safe APIs. Check required pointer validity before dereference; a null check alone is insufficient.
Check: Compiler typing, candidate checks for integer-fabricated null pointers, and foreign API review.
Coverage limit: Raw null pointers can be created in safe Rust. Non-nullness alone establishes neither allocation validity nor lifetime/alignment.
SCR-RUST-018: Make mixed-operator intent clear#
Proposed level: Advisory. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.0.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production expressions.
Expressions mixing arithmetic, bitwise, shift or Boolean operators should use grouping that makes the intended evaluation clear. Split complex expressions when parentheses alone do not make them readable.
Check: Clippy precedence and code review.
Coverage limit: A precedence lint detects only selected patterns; this remains partly a readability judgment.
SCR-RUST-019: Use checked type recovery#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.2.1 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Type-erased values and trait-object downcasts.
Recover concrete types through checked APIs such as Any downcasts, and handle failure. Unchecked type recovery requires a proven type-identity invariant within an approved unsafe abstraction. Do not invent a ban on ordinary TypeId queries.
Check: API inventory, compiler type checks and review of unchecked downcast/representation operations.
Coverage limit: A checked downcast establishes type identity at the point of the call only; it does not establish that the recovered value satisfies the invariants the caller expects, and a failed downcast still needs a defined error path. Only an inventory of unchecked recovery (transmute, pointer casts) finds bypasses. Ordinary checked native APIs need no custom MISRA-shaped check.
SCR-RUST-020: Restrict pointer casts and representation changes#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.2.3 (SCRC draft: unsafe), 8.2.5 (SCRC draft: unsafe), 8.2.6 (SCRC draft: unsafe), 8.2.7 (SCRC draft: unsafe), 8.2.8 (SCRC draft: safe), 23.11.1 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: All raw-pointer transformations, safe and unsafe.
Prefer typed pointer/reference APIs. Pointer-to-integer conversions, reconstruction of pointers,
mutability-changing casts and transmute shall be restricted to reviewed low-level interfaces with
documented provenance, alignment, validity and aliasing assumptions. Do not truncate addresses or
fabricate a mutable reference from shared access outside valid interior-mutability rules. Creating
an owning value from a raw pointer (Box::from_raw, Vec::from_raw_parts,
CString::from_raw, Rc::from_raw, Arc::from_raw and similar; 23.11.1) shall satisfy that
API’s producer, allocation and ownership preconditions: the pointer came from the matching
into_raw or from an allocation with the same layout, ownership is transferred exactly once, and
for Rc/Arc the reference-count accounting (from_raw paired with into_raw or
increment_strong_count) is documented. The resulting ownership obligations follow SCR-RUST-035.
Check: Candidate Clippy pointer/transmute lints and API restrictions; compiler invalid-reference diagnostics; custom AST inventory, unsafe review and Miri where applicable.
Coverage limit: Many pointer casts are legal outside unsafe. Inventory the entire crate; transmute is not a generally safer replacement for as. Provenance correctness cannot be inferred from equal sizes.
SCR-RUST-021: Preserve function-call ABI and variadic contracts#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.2.4 (SCRC draft: unsafe), 8.2.11 (SCRC draft: unsafe), 21.10.1 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Function pointers, callbacks and variadic foreign calls.
Calls shall use a compatible function signature, calling convention and ABI. Function-pointer
representation changes require boundary review. Defining C-variadic functions in Rust is prohibited
in first-party production code (21.10.1; the feature is unstable and its VaList handling is
unsafe). Calling a foreign variadic function is limited to a reviewed adapter that validates
argument types and applicable promotion rules (8.2.11).
Check: Compiler ABI/type diagnostics, binding generation checks, adapter review and cross- language integration tests.
Coverage limit: A successful link does not validate an incorrectly declared foreign signature or variadic argument contract. The paper excludes full FFI analysis.
SCR-RUST-022: Control recursion and stack consumption#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.2.10 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production call paths, including callbacks and recursive destruction.
Related draft SCRC guideline: gui_ot2Zt3dd6of1 (recursion, for 8.2.10). This rule is to be reconciled with the SCRC text as it matures.
Direct and indirect recursion that executes at runtime shall be prohibited in production call paths
unless a scoped deviation establishes a finite depth and stack budget. Recursion in a const fn
is permitted when the call is evaluated in a constant context, where the compiler bounds it through
the const-evaluation limit; the same const fn called at runtime falls under the prohibition
(adaptation of the constexpr exception in 8.2.10). Assess recursive parsing, traversal and
destructor chains as well as explicit self-calls.
Check: Compiler unconditional_recursion provides a narrow check; candidate CodeQL/call-graph analysis and stack/depth testing provide additional evidence.
Coverage limit: Unconditional-recursion diagnostics do not detect all terminating recursion. Dynamic dispatch, callbacks and foreign calls leave call-graph gaps; static analysis is not a general proof of bounded stack use.
SCR-RUST-023: Respect allocation boundaries in pointer operations#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.7.1 (SCRC draft: unsafe), 8.7.2 (SCRC draft: unsafe), 8.9.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Raw-pointer arithmetic, differences, comparisons and later use.
Pointer operations shall meet their individual API contracts, including allocation/provenance and bounds requirements. Relational comparisons shall not infer object order across unrelated allocations. Prefer slice indexing/iteration; document any reviewed address-ordering exception separately.
Check: Unsafe review, targeted Miri tests, and candidate checks for pointer operations and their data flow.
Coverage limit: Some construction, wrapping arithmetic and comparisons are safe operations. An out-of-bounds intermediate is not universally forbidden by Rust; the applicable API and eventual access determine validity. The project comparison restriction is stronger than language UB rules.
Example:
// Compliant: no access occurs during the wrapping excursion.
fn read_first() -> u8 {
let bytes = [1_u8, 2];
let p = bytes.as_ptr();
let q = p.wrapping_add(20).wrapping_sub(20);
// SAFETY: q is back at the initialized first byte; bytes is still live.
unsafe { *q }
}
// Non-compliant: add(20) itself exceeds its permitted bounds.
fn read_first() -> u8 {
let bytes = [1_u8, 2];
let p = bytes.as_ptr();
let q = unsafe { p.add(20) }.wrapping_sub(20);
unsafe { *q }
}
Both function bodies compile and both are operations inside a reviewed low-level implementation; the
pointer remains derived from the live two-byte array. Miri accepts the first and reports undefined
behavior at add(20) in the second, before the read, because add requires the result to stay
in bounds while wrapping_add does not. The individual pointer API contract decides, not the
final address.
SCR-RUST-024: Separate persistent effects from short-circuit decisions#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.14.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production Boolean expressions.
Level rationale: Required although Rule 8.14.1 is Advisory: a state change skipped because the left operand short-circuits the expression alters program behavior silently and is not diagnosed by the compiler.
Required persistent effects shall not depend on accidental short-circuit evaluation. A state change
or I/O on the right side of && or || is acceptable only when skipping it is the specified
behavior whenever the left operand decides the expression, and the call site documents that
conditional-effect contract, for example filling a cache entry that is correctly skipped when the
entry is already present. Otherwise move the effect out of the condition.
Check: Candidate AST checks for obvious mutations and CodeQL effect/call analysis; code review.
Coverage limit: Identifying arbitrary side effects through calls requires models. A function call in a condition is not automatically a violation.
SCR-RUST-025: Use memory-copy operations with valid overlap and ownership#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 8.18.1 (SCRC draft: unsafe), 24.5.2 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Raw copies and buffer movement.
Choose copy operations whose overlap contract matches the buffers: copy_nonoverlapping requires
disjoint regions; overlapping movement must use ptr::copy. The copy operation itself requires
valid, aligned, in-bounds pointers for the element count, the overlap condition of the chosen API,
and ownership handling without double drop; it may copy uninitialized storage such as
MaybeUninit buffers. Using the destination as an initialized T is a separate step that
requires T’s validity invariant to hold for the copied bytes, since the raw copy preserves
uninitialized padding. Byte-wise comparison of whole objects is permitted only where every compared
byte is initialized and accessible under valid lifetime and aliasing conditions, and byte equality
is the intended equality; otherwise compare semantically through PartialEq. This conditional
permission is an adaptation of 24.5.2’s ban on the C++ memory functions.
Check: API review, boundary tests and Miri; candidate checks for raw copy calls and buffer relationships.
Coverage limit: ptr::copy permits overlap; the C++ rule cannot become a blanket ban on
overlap without changing its intent. repr(C) and Copy do not establish that padding is
initialized, and even a valid byte view compares differently from value equality for signed zero or
unused buffer bytes.
SCR-RUST-026: Specify arithmetic overflow and shift behavior#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 7.0.4 (SCRC draft: safe), 8.20.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Integer arithmetic, shifts and constant calculations.
Related draft SCRC guideline: gui_RHvQj8BHlz9b (shift-count bounds, for 7.0.4). This rule is to be reconciled with the SCRC text as it matures.
Arithmetic shall stay within its required range or use explicit checked, saturating, wrapping or
overflowing operations with justified semantics. A shift count shall be non-negative and less than
the bit width of the left operand’s type, the criterion shared with the draft SCRC guideline for
7.0.4. Division and remainder shall check for a zero divisor and for MIN / -1. Constants shall
not silently wrap contrary to their intended value (8.20.1). The policy for general runtime
arithmetic is an S-CORE extension; the two MISRA C++ sources address shift counts and constant
expressions.
Check: Compiler constant/overflow diagnostics; Clippy arithmetic_side_effects as a candidate restriction; boundary tests under the delivered build settings.
Coverage limit: Panic and release-mode behavior depend on the operation and the delivered overflow-check setting; a shift by an out-of-range count panics in debug and masks in release unless overflow checks are on.
SCR-RUST-027: Make decision fallbacks explicit#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 9.4.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production if/else-if decision chains.
Each if/else-if chain with two or more conditions shall define behavior when no condition matches.
Prefer an exhaustive match for finite cases; otherwise provide a final else that performs
the defined fallback or documents the intentionally empty action. The rule applies to all production
chains, as 9.4.1 does; a single if without else if is an independent guard and is not
affected.
Check: Compiler match exhaustiveness; candidate syntax check for missing final else; review of fallback requirements.
Coverage limit: A final else or wildcard arm does not prove that the fallback is correct.
SCR-RUST-028: Separate volatile I/O from synchronization#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 10.1.2 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Hardware access and volatile operations.
Volatile operations shall be confined to reviewed hardware/platform abstractions with documented address, width, alignment and device-ordering assumptions. Use appropriate synchronization for shared memory; volatile shall not be used as a substitute for atomics or locks.
Check: API restriction/inventory, platform review and hardware integration tests.
Coverage limit: Miri and host tests do not establish real device behavior. Validity requirements differ for the specific I/O operation and memory region.
SCR-RUST-029: Restrict assembly to reviewed platform modules#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 10.4.1 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Inline and global assembly.
Assembly is prohibited in ordinary application components. A platform exception shall document the instruction contract, registers/clobbers, stack, memory effects, target assumptions and safe wrapper invariants.
Check: Source/macro inventory, compiler assembly checks and specialist review of each exception.
Coverage limit: Compiler acceptance does not establish correctness of declared assembly effects. Scan generated and macro-expanded code too.
SCR-RUST-030: Limit raw-pointer indirection#
Proposed level: Advisory. Source IDs (MISRA C++:2023, draft SCRC assessment): 11.3.2 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Raw-pointer APIs and declarations.
Raw-pointer interfaces should use no more than two pointer-indirection levels. Deeper foreign interfaces should be isolated behind a typed adapter with explicit ownership and extent contracts. Native references and smart-pointer composition require separate design assessment.
Check: A type-aware syntax check and interface review.
Coverage limit: Indirection count is a complexity restriction, not proof of memory safety;
benign safe abstractions must not be classified solely by textual asterisks. Scope choice: the SCRC
draft assesses 11.3.2 as applicable to safe Rust because it includes references. This rule
deliberately counts raw pointers only; reference and smart-pointer composition such as &&T or
Box<Rc<T>> is left to the component’s design assessment because the type system makes that
nesting explicit and checked.
SCR-RUST-031: Establish initialization and value validity before use#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 11.6.1 (SCRC draft: unsafe), 11.6.2 (SCRC draft: unsafe), 15.1.4 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Native initialization, MaybeUninit, unions and raw storage.
Every value observed as its type T shall be initialized and valid for T. For
MaybeUninit<T> and raw storage the requirement applies to producing or accessing the payload as
T: assume_init, assume_init_ref/assume_init_mut, ptr::read as T, and
creating &T or &mut T. Operations on the container are not restricted: taking &mut
MaybeUninit<T>, calling MaybeUninit::write, and reading or copying storage as
MaybeUninit<T> or as bytes are valid while the payload is uninitialized. Track partial
initialization and avoid duplicate destruction. Zero-filled storage shall not be treated as a valid
arbitrary T.
Check: Compiler definite-initialization checks; unsafe review and Miri tests for low-level storage; candidate inventories for initialization-bypassing APIs.
Coverage limit: Compiler checks for ordinary locals do not establish initialization of raw
storage. Creating &T to an invalid value is already undefined behavior, before any explicit
read; Miri detects such payload accesses on executed paths.
SCR-RUST-032: Prefer enums over untagged unions#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 12.3.1 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Application data models and foreign/low-level representations.
Use enums for application alternatives. A union shall be confined to a justified representation boundary with a documented discriminant/active-field protocol, field validity and destruction policy.
Check: Syntax inventory and review of each union definition/access; targeted tests.
Coverage limit: Rust union reads have validity obligations that a documented active-field name alone cannot satisfy. FFI layout may require a reviewed exception.
SCR-RUST-033: Make parameter roles consistent#
Proposed level: Advisory. Source IDs (MISRA C++:2023, draft SCRC assessment): 13.3.3 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Trait methods, implementations and public API documentation.
Level rationale: Advisory although Rule 13.3.3 is Required: Rust has neither default arguments nor overload sets, so the residual concern is consistent naming of parameter roles across trait and implementation signatures, which the compiler accepts either way.
Parameter names should consistently describe their semantic roles across trait declarations, implementations and examples. Mark intentionally unused parameters explicitly and explain why an implementation ignores them.
Check: Compiler unused_variables and API review; optional trait/implementation name comparison.
Coverage limit: Rust permits unnamed patterns such as _. This adaptation concerns readable contracts, not C++ overriding syntax.
Example:
trait Distance {
fn millimetres(&self, metres: u32) -> u64;
}
struct Converter;
impl Distance for Converter {
// Compliant: preserves the parameter's stated role.
fn millimetres(&self, metres: u32) -> u64 {
u64::from(metres) * 1000
}
}
trait Distance {
fn millimetres(&self, metres: u32) -> u64;
}
struct Converter;
impl Distance for Converter {
// Non-compliant: seconds misstates the parameter's role.
fn millimetres(&self, seconds: u32) -> u64 {
u64::from(seconds) * 1000
}
}
Both compile and produce the same result. The second describes a distance as a duration, a semantic mismatch the compiler accepts.
SCR-RUST-034: Protect type invariants through visibility#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 14.1.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Struct fields and constructors.
Level rationale: Required although Rule 14.1.1 is Advisory: visibility is the only language mechanism that protects a type invariant in Rust; a public field lets safe code create an invalid state without any diagnostic.
Fields whose arbitrary mutation can violate an invariant shall be private and changed through validating APIs. Plain data carriers may expose fields when all representable states are valid for their contract. Review mixed visibility explicitly.
Check: API/design review; custom checks may inventory public fields and constructor bypasses.
Coverage limit: Making every field public or private does not itself prove invariant preservation. This replaces the C++ structural recommendation with a Rust invariant-oriented policy.
Example:
// Compliant: callers outside the module cannot bypass validation.
mod percentage {
pub struct Percent { value: u8 }
impl Percent {
pub fn new(value: u8) -> Option<Self> {
if value <= 100 { Some(Self { value }) } else { None }
}
pub fn value(&self) -> u8 { self.value }
}
}
// Non-compliant for the same invariant: callers can bypass validation.
mod percentage {
pub struct Percent { pub value: u8 }
}
fn break_invariant() {
let mut p = percentage::Percent { value: 50 };
p.value = 101;
}
Both compile. Percent promises a value in 0..=100; the second permits an invalid state through
safe public access.
SCR-RUST-035: Review ownership traits and resource lifecycle#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 15.0.1 (SCRC draft: safe), 15.8.1 (SCRC draft: unsafe), 21.6.2 (SCRC draft: safe), 28.6.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Copy/Clone/Drop, pinning, custom owners and raw allocation wrappers.
Copy/Clone/Drop implementations shall preserve ownership and type invariants. Every acquired
resource shall have a defined release/transfer policy, including partial failure paths. Unsafe
pinning abstractions shall preserve their promised pinning invariants. Do not rely on destructors
running to maintain memory safety. Synchronization/resource guards shall remain bound for the
intended duration; do not accidentally discard them immediately. Where a borrowed-to-owned
conversion matters, use an explicit operation such as to_vec(), to_owned() or clone()
rather than a generic From/Into call whose behavior, moving an owner or copying from a
borrow, depends on the argument type (adaptation of 28.6.1). APIs that emulate move or assignment
through raw pointers, including Pin-based move emulation and in-place replacement, shall define
behavior when source and destination coincide: either the aliasing case preserves the value,
invariants and resources, or it is an explicit unsafe precondition that every safe wrapper
establishes (adaptation of Directive 15.8.1).
Check: Compiler move/trait checks, review of custom implementations and targeted Miri/resource- failure tests; inventory mem::forget, leaks and manual ownership transfer. Include the rustc let_underscore_lock diagnostic where supported.
Coverage limit: Safe Rust permits leaks and mem::forget, and termination may skip Drop.
Pin is a type, not a trait. The compiler decides whether a generic conversion moves or copies,
but a reader cannot see which without an explicit operation.
SCR-RUST-036: Define panic, termination and cleanup behavior#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 18.1.1 (SCRC draft: unsafe), 18.4.1 (SCRC draft: safe), 18.5.1 (SCRC draft: safe), 18.5.2 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Production library code, process boundaries and destructors.
Recoverable failures shall use explicit error handling. Application libraries shall not terminate
the process directly or indirectly: calling std::process::exit or abort, taking or storing
their addresses, or reaching them through foreign code is prohibited; the only accepted fail-stop is
the abort produced by a failed assertion or by the delivered panic strategy, and any broader fail-
stop path requires a documented system response including cleanup or external recovery (adaptation
of 18.5.2). Two levels are distinguished per boundary: a panic-free path never initiates a
panic, including implicit panics from indexing, arithmetic and allocation; a panic-contained
boundary may see a panic but shall not let it escape. Destructors are panic-free: a custom Drop
and the field cleanup it relies on shall not panic (18.4.1). Catching a panic with catch_unwind
to convert it into an error is acceptable only on a panic-contained boundary under panic=unwind,
and the code after the catch, including dropping the payload and any guards, shall itself be panic-
free; under panic=abort catching cannot recover, and a panic during unwinding terminates. No
panic shall cross a foreign-language boundary (18.5.1; see SCR-RUST-042). Panic payloads passed to
panic_any shall carry only owned data or 'static references; wrappers, integer addresses or
handles that give access to borrowed non-'static storage are prohibited (adaptation of 18.1.1;
permitting 'static references is a Rust adaptation of the C++ pointer restriction). Account for
allocation failure and the panic strategy; keep critical fallible cleanup in explicit APIs.
Check: Selected Clippy panic/unwrap_used/expect_used restrictions; clippy::exit for direct
calls plus an inventory of stored or passed function pointers to termination APIs; failure-injection
tests and call-path review; Miri or tests for destructor panic paths.
Coverage limit: Absence of panic! and unwrap does not prove panic freedom: indexing,
arithmetic, dependencies and destructors can fail. clippy::exit sees direct calls only. Panic is
not synonymous with Rust undefined behavior; the system may nevertheless treat it as a safety
failure.
SCR-RUST-037: Validate attributes and configuration coverage#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 19.0.1 (SCRC draft: not applicable, retained by S-CORE).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: cfg/features, attributes and build-generated configuration.
All cfg names/values and features shall be declared and checked. Invalid or unrecognized attributes/configuration diagnostics shall block analysis. Maintain and analyze the supported configuration matrix, including mutually exclusive features, rather than assuming one all-features build is representative.
Check: rustc unexpected_cfgs and appropriate check-cfg flags, attribute diagnostics, build- matrix checks and configuration review.
Coverage limit: Inactive code is not necessarily type-checked. Correct configuration syntax does not establish that every delivered variant was analyzed.
Example:
// Compliant feature spelling.
#[cfg(feature = "enabled")]
fn feature_marker() {}
fn main() {}
// Non-compliant: undeclared, misspelled feature value.
#[cfg(feature = "enabeld")]
fn feature_marker() {}
fn main() {}
With the only declared feature value being enabled and --check-cfg 'cfg(feature,
values("enabled"))' -D unexpected_cfgs, the first passes and the second is rejected by the
unexpected_cfgs lint even though the feature is inactive. See the rustc check-cfg documentation.
SCR-RUST-038: Control macro expansion and argument effects#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 19.0.2 (SCRC draft: safe), 19.3.4 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Declarative/procedural macros and generated Rust.
Prefer a function where a function can express the intended behavior. A macro is justified for variadic arity, item or implementation generation, compile-time token or string processing, or capturing the caller location, and the crate shall state which of these exceptions it uses (adaptation of 19.0.2). Macros shall document whether arguments are evaluated once, more than once or not at all. Use expression fragments where expression semantics are intended. Safety-relevant macro-generated unsafe code and effects shall be included in review and checker coverage.
Check: Macro expansion inspection, tests using arguments with observable effects, and lint coverage checks on generated code.
Coverage limit: Rust macros avoid some C++ textual-substitution hazards but can still duplicate evaluation, introduce panics or unsafe code. Compiler type checking is not a substitute for semantic review.
SCR-RUST-039: Bound allocation and isolate manual allocators#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 21.6.1 (SCRC draft: safe), 21.6.3 (SCRC draft: unsafe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Heap allocation, container growth and custom allocation.
Each component shall declare where allocation is permitted and justify peak memory, growth limits and failure behavior. Unbounded input-driven growth is prohibited. Manual allocators and raw allocation APIs shall be restricted to reviewed modules with allocator/layout/ownership contracts.
Check: Allocation API inventory, workload/boundary/failure tests and memory-budget review; candidate CodeQL flow checks for untrusted size inputs.
Coverage limit: A blanket no-allocation profile is an optional stricter component policy, not silently imposed here. try_reserve covers only particular failures; RAII does not bound memory, prevent leaks or guarantee recovery from OOM.
SCR-RUST-040: Separate compile-time and runtime assertions#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 22.3.1 (SCRC draft: safe).
Origin: S-CORE interpretation of MISRA C++:2023 guidelines. Scope: Assertions and invariant checks.
An invariant intended for compile-time checking shall use a const-evaluated construct supported by the pinned compiler. Required runtime validation shall remain active in production and return the specified error or enter the approved failure path. Do not put required side effects inside debug_assert!.
Check: Compiler const evaluation; Clippy assertions_on_constants as a candidate; release- configuration tests and assertion review.
Coverage limit: A constant argument to an ordinary assert! does not by itself request const evaluation. debug_assert! can be disabled and must not carry a required safety check.
Example:
// Compliant: the check remains active in production.
fn check(value: u8) -> Result<(), ()> {
if value <= 10 { Ok(()) } else { Err(()) }
}
// Non-compliant: the required check can disappear.
fn check(value: u8) -> Result<(), ()> {
debug_assert!(value <= 10);
Ok(())
}
Both compile. The API must reject values above 10 in production builds too; with -C debug-
assertions=no the second returns Ok(()) for 11. debug_assert! is conditional on that build
setting and cannot carry a required runtime check.
SCR-RUST-041: Account for dependency and generated-code soundness#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): No direct mapping.
Origin: S-CORE supplement (dependency and generated-code soundness). Scope: Transitive crates, standard library assumptions, macros and generators.
Maintain the dependency/generator inventory and record the evidence relied on for unsafe implementations, feature selection and foreign code. Component safe-only status shall describe first-party source scope separately from the full linked dependency graph.
Check: Dependency lock/configuration review, unsafe/binding inventories, change-impact review and relevant integration tests.
Coverage limit: No-unsafe in first-party source is not a soundness proof for dependencies. The paper analyzes language constructs, not the delivered dependency graph.
SCR-RUST-042: Assess foreign-language boundaries explicitly#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): 18.5.1 (SCRC draft: safe), 21.10.2 (SCRC draft: unsafe), 21.10.3 (SCRC draft: unsafe), 22.4.1 (SCRC draft: unsafe), 25.5.1 (SCRC draft: unsafe), 25.5.2 (SCRC draft: unsafe), 25.5.3 (SCRC draft: unsafe).
Origin: S-CORE supplement informed by MISRA C:2025 Addendum 6. Scope: Every Rust/C/C++ boundary.
Foreign bindings shall match the actual ABI, layout, types and exported definitions. Document
ownership, pointer/length contracts, threading and callback lifetime, error conventions and
unwinding behavior in both directions. Unwinding: no Rust panic shall reach a foreign frame and no
foreign exception shall enter Rust. Functions exported or imported through extern "C" shall be
panic-contained on the Rust side (see SCR-RUST-036) and the foreign side shall not throw across
them; extern "C-unwind" may be used only when both sides support unwinding and the delivered
panic strategy is unwind; catch_unwind shall not be relied on to recover foreign exceptions or
aborts (18.5.1). Nonlocal transfers: setjmp/longjmp and similar shall not cross a Rust
frame; foreign-only use stays inside the foreign region under that code’s own policy (21.10.2).
Signals: signal handling is limited to the platform APIs the component documents, a handler requires
an async-signal-safety assessment, and disabling a signal is permitted where documented (21.10.3
exception). Error state: handle errno and equivalents per the API contract, reading it only when
the return value makes it meaningful, clearing it before the call where the API requires, and
capturing it before logging or any other call can overwrite it; application code shall not write
errno except to assign a literal zero directly or through a constant that expands to it,
computed values included as an S-CORE adaptation are not permitted (22.4.1);
std::io::Error::last_os_error reads GetLastError on Windows and is not a portable
substitute. Locale: Rust code shall not change the process-wide locale (25.5.1); a component that
must do so shall document initialization ordering and concurrency conditions for all affected
foreign code as an explicit adaptation. Returned storage: storage returned by localeconv,
getenv, setlocale and strerror, including strings nested in lconv, shall be treated
as read-only; a shared reference created from it, including through CStr::from_ptr, is valid
only while no foreign code can mutate the storage, and an owned snapshot shall be taken by a valid,
race-free read of the whole data including nested strings; the addresses of these four functions
shall not be taken or stored for indirect calls (25.5.2, adopted). Pointers returned by asctime,
ctime, gmtime, localtime, localeconv, getenv, setlocale and strerror
shall not be used after a later call, on any thread, to the same function or to one that invalidates
the same storage, such as setlocale after localeconv, asctime/ctime and
gmtime/localtime; copy the data while the read is valid and protected (25.5.3). Assess C/C++
implementations under their own applicable policy.
Check: MISRA C:2025 Addendum 6 cross-check, binding/layout/symbol review and tests on delivered targets. Its explicit comments on R.8.3, R.8.5, R.8.6 and R.8.15 provide boundary cross-references.
Coverage limit: MISRA C:2025 Addendum 6 is an applicability assessment with 223 guideline entries. S-CORE has not yet derived and checked an obligation for every MISRA C guideline the addendum assesses as applicable to Rust boundaries; this supplement covers the boundary concerns of its linked MISRA C++ sources and the addendum comments on R.8.3, R.8.5, R.8.6 and R.8.15. Completing that derivation is open work for a later rulebook revision.
SCR-RUST-043: Record coverage, deviations and residual obligations#
Proposed level: Required. Source IDs (MISRA C++:2023, draft SCRC assessment): No direct mapping.
Origin: S-CORE governance supplement. Scope: Every adopted guideline and delivered configuration.
Each required adopted rule shall have evidence of conformance or an approved scoped deviation. Record rule version, configuration, checker version, known blind spots and review/test evidence. Advisory nonconformances shall be considered and dispositioned. Safety-relevant liveness, timing and persistence guarantees need separate requirements and verification.
Check: Rule-to-checker coverage register, deviation validation and release evidence review. Separate test/tooling profiles shall not suppress production library obligations.
Coverage limit: A clean lint/SARIF report proves neither full rule coverage nor functional safety. This draft defines obligations; it installs no checker and grants no approval.