From 825ab8476ad7052919d8cac05d0e01ae110ade4a Mon Sep 17 00:00:00 2001 From: akriso Date: Mon, 18 Aug 2025 16:28:24 +0200 Subject: [PATCH 1/2] Add guideline requiring wrapping unsafe in safe abstractions --- src/coding-guidelines/unsafety.rst | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/coding-guidelines/unsafety.rst b/src/coding-guidelines/unsafety.rst index e8e1319..cd05fc9 100644 --- a/src/coding-guidelines/unsafety.rst +++ b/src/coding-guidelines/unsafety.rst @@ -5,3 +5,66 @@ Unsafety ======== + +.. guideline:: All unsafe code shall be contained inside a sound safe abstraction + :id: gui_goekLVFUAjSM + :category: required + :status: draft + :release: - + :fls: fls_jep7p27kaqlp + :decidability: undecidable + :scope: module + :tags: undefined-behavior + + A safe abstraction is considered sound, when it is impossible to build a **safe** program using + the safe abstraction that invokes undefined behavior. + + Safe abstractions shall be kept as small as possible and only include features that cannot be built + on top in safe Rust. + + .. rationale:: + :id: rat_3FoizIv2mZ4Z + :status: draft + + Unsound safe abstractions leak the possibility for undefined behavior to safe Rust. + With violations of this rule, it would no longer suffice to only focus on unsafe modules + as the root cause of undefined behavior + + Because safe abstractions are more difficult to review compared to safe code due to the + subtle semantics of unsafe operations, their size need to be minimized. + + .. non_compliant_example:: + :id: non_compl_ex_4Rj4YQkr1Nr4 + :status: draft + + The following module with a safe API uses unsafe code and is therefore a safe abstraction. + However, when passing a data slice with an index that is outside the range of the slice, + the safe function will cause undefined behavior. + + .. code-block:: rust + + mod bad { + fn get_value(data: &[i32], index: usize) -> i32 { + unsafe { + data.get_unchecked(usize) + } + } + } + + .. compliant_example:: + :id: compl_ex_aM7w7UbgSdvT + :status: draft + + This safe module checks that its argument are valid, (i.e., they satisfy the safety + precondition of the unsafe operation) before performing the unsafe operation. + + .. code-block:: rust + + mod good { + fn get_value(data: &[i32], index: usize) -> i32 { + assert!(usize < data.len()); + unsafe { + data.get_unchecked(usize) + } + } + } From fc7280a143a53aefd7fea42bb6f716a1b79001d0 Mon Sep 17 00:00:00 2001 From: akriso Date: Mon, 18 Aug 2025 17:47:31 +0200 Subject: [PATCH 2/2] Make example items pub --- src/coding-guidelines/unsafety.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coding-guidelines/unsafety.rst b/src/coding-guidelines/unsafety.rst index cd05fc9..32f4464 100644 --- a/src/coding-guidelines/unsafety.rst +++ b/src/coding-guidelines/unsafety.rst @@ -43,8 +43,8 @@ Unsafety .. code-block:: rust - mod bad { - fn get_value(data: &[i32], index: usize) -> i32 { + pub mod bad { + pub fn get_value(data: &[i32], index: usize) -> i32 { unsafe { data.get_unchecked(usize) } @@ -60,8 +60,8 @@ Unsafety .. code-block:: rust - mod good { - fn get_value(data: &[i32], index: usize) -> i32 { + pub mod good { + pub fn get_value(data: &[i32], index: usize) -> i32 { assert!(usize < data.len()); unsafe { data.get_unchecked(usize)