Skip to content

Commit 4a507dc

Browse files
vapdrsPLeVasseurfelix91gr
authored
[Guideline] Add safe division guideline to avoid dividing by zero (rustfoundation#136)
* Add checked arithmetic guidelines * Add more typo ignore patterns These correspond to the unique ID's for each section. * Remove floating point types from these guidelines * Ensure example match * Add statement to rationale justifying the Advisory * Correct typos * Update comment for directive typo check Co-authored-by: Pete LeVasseur <[email protected]> * Expound upon `unchecked_` functions Additionally the code block formatting was updating, and a link was added. Co-authored-by: Pete LeVasseur <[email protected]> * Fix grammar of wrap around * Change sphinx link syntax * Add link to FLS ArithmeticExpression * Correct description of unchecked function As pointed out, they result in UB not necessarily panics * Remove other mention of panics * Narrow guideline to just integer division. * Remove guideline on unchecked methods As those are marked unsafe anyway * Add remainder expression example * Downgrade this to an advisory guideline It could get annoying in existing codebases * Fix missing commas for syntax * Add subset tag * Word choice as suggested by Felix * Formatting * Apply suggestions from code review Spelling and word choice from review Co-authored-by: Félix Fischer <[email protected]> * Example clarification from code review Co-authored-by: Félix Fischer <[email protected]> * Note clarity and rewording Co-authored-by: Félix Fischer <[email protected]> --------- Co-authored-by: Pete LeVasseur <[email protected]> Co-authored-by: Félix Fischer <[email protected]>
1 parent f4b4f89 commit 4a507dc

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

_typos.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
[default]
22
extend-ignore-identifiers-re = [
3-
# Ignore things that look like gui_xztNdXA2oFNB
3+
# Ignore Sphinx directives for typos
44
"gui_.*",
5+
"rat_.*",
6+
"compl_ex_.*",
7+
"non_compl_ex_.*",
58
]
69

src/coding-guidelines/expressions.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,70 @@ Expressions
8282
8383
fn with_base(_: &Base) { ... }
8484
85+
.. guideline:: Do not use integer type as divisor
86+
:id: gui_7y0GAMmtMhch
87+
:category: advisory
88+
:status: draft
89+
:release: latest
90+
:fls: fls_Q9dhNiICGIfr
91+
:decidability: decidable
92+
:scope: module
93+
:tags: numerics, subset
94+
95+
This guideline applies when a `DivisionExpression
96+
<https://rust-lang.github.io/fls/expressions.html#syntax_divisionexpression>`_ or `RemainderExpression
97+
<https://rust-lang.github.io/fls/expressions.html#syntax_remainderexpression>`_ is used with a RightOperand of
98+
`integer type <https://rust-lang.github.io/fls/types-and-traits.html#integer-types>`_.
99+
100+
.. rationale::
101+
:id: rat_vLFlPWSCHRje
102+
:status: draft
103+
104+
The built-in semantics for these expressions can result in panics when division by zero occurs. It is
105+
recommended to either:
106+
107+
* Use checked division functions, which ensure the programmer handles the case when the divisor is zero, or
108+
* To create divisors using :std:`std::num::NonZero`, which then allows the programmer to perform those
109+
operations knowing that their divisor is not zero.
110+
111+
**Note:** since the compiler can assume the value of a :std:`std::num::NonZero`
112+
variable to not be zero, checks for zero when dividing by it can be elided in the
113+
final binary, increasing overall performance beyond what normal division can have.
114+
115+
.. non_compliant_example::
116+
:id: non_compl_ex_0XeioBrgfh5z
117+
:status: draft
118+
119+
When either the division or remainder are performed, the right operand is evaluated to zero and the
120+
program panics.
121+
122+
.. code-block:: rust
123+
124+
let x = 0;
125+
let y = 5 / x; // This line will panic.
126+
let z = 5 % x; // This line would also panic.
127+
128+
.. compliant_example::
129+
:id: compl_ex_k1CD6xoZxhXb
130+
:status: draft
131+
132+
There is no compliant way to divide with an integer type. Here, instead, the developer explicitly:
133+
134+
* Uses a checked division function, which ensures a zero divisor is handled separately, and
135+
* Creates a divisor using :std:`std::num::NonZero`, which outsources the check for zero to the
136+
construction of that struct. It's worth noting that such a divisor can be used multiple times after it's been created, whilst keeping the guarantee that such divisions will be safe.
137+
138+
.. code-block:: rust
139+
140+
let x = 0;
141+
if let Some(divisor) = match NonZero::<u32>::new(x) {
142+
let result = 5 / divisor;
143+
}
144+
let result = match 5u32.checked_rem(x) {
145+
None => 0,
146+
Some(r) => r,
147+
}
148+
85149
86150
.. guideline:: Do not divide by 0
87151
:id: gui_kMbiWbn8Z6g5

0 commit comments

Comments
 (0)