Skip to content

[Guideline] Add checked arithmetic guidelines #136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion _typos.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[default]
extend-ignore-identifiers-re = [
# Ignore things that look like gui_xztNdXA2oFNB
# Ignore Sphinx directives for typos
"gui_.*",
"rat_.*",
"compl_ex_.*",
"non_compl_ex_.*",
]

101 changes: 101 additions & 0 deletions src/coding-guidelines/expressions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,104 @@ Expressions
}

fn with_base(_: &Base) { ... }

.. guideline:: Do not use builtin integer arithmetic expressions
:id: gui_7y0GAMmtMhch
:category: required
:status: draft
:release: latest
:fls: fls_Q9dhNiICGIfr
:decidability: decidable
:scope: module
:tags: numerics

This guideline applies when an `ArithmeticExpression
<https://rust-lang.github.io/fls/expressions.html#arithmetic-expressions>`_ is used with operands of
integer type.

.. rationale::
:id: rat_vLFlPWSCHRje
:status: draft

The built-in semantics for these expressions can result in panics, or silent wrap around upon overflow
or division by zero occurs. It is recommended to explicitly declare what should happen during these
events with checked arithmetic functions.

.. non_compliant_example::
:id: non_compl_ex_0XeioBrgfh5z
:status: draft

When the division is performed, the right operand is evaluated to zero and the program panics.
When the addition is performed, either silent overflow happens or a panic depending on the build
configuration.

.. code-block:: rust

let x = 0;
let x = 5 / x;
let y = 135u8
let y = 200u8 + y;

.. compliant_example::
:id: compl_ex_k1CD6xoZxhXb
:status: draft

The developer must explicitly indicate the intended behavior when a division by zero or arithmetic
overflow occurs when using checked arithmetic methods.

.. code-block:: rust

let x = 0;
let result = match 5u32.checked_div(x) {
None => 0
Some(r) => r
}
let y = 135u8
let y = 200u8.wrapping_add(y);

.. guideline:: Do not use unchecked integer arithmetic methods
:id: gui_mNEvznFjC3kG
:category: advisory
:status: draft
:release: latest
:fls: fls_Q9dhNiICGIfr
:decidability: decidable
:scope: module
:tags: numerics

This guideline applies to any call to the integer type methods that begin with ``unchecked_``, such as
`core::primitive::u8::unchecked_add <https://doc.rust-lang.org/std/primitive.u8.html#method.unchecked_add>`_.

.. rationale::
:id: rat_7tF18FIwSYws
:status: draft

The semantics for these expressions can result in undefined behavior in situations where an equivalent
checked operation would return ``None``. It is recommended to explicitly declare what should happen
during these events with checked arithmetic functions.

In a particularly performance sensitive critical section of the code it may be necessary to use the
unchecked methods in tandem with assurances that the arguments will never meet the undefined behavior
conditions.

.. non_compliant_example::
:id: non_compl_ex_JeRRIgVjq8IE
:status: draft

When the multiplication is performed, the evaluation could result in undefined behavior.

.. code-block:: rust

let x = 13u8.unchecked_mul(y);

.. compliant_example::
:id: compl_ex_HIBS9PeBa41c
:status: draft

If arithmetic overflow would have occurred during the multiplication operation this method will ensure
that the returned value is the bounding of the type. The intention is clear in that case.

.. code-block:: rust

let x = 13u8.saturating_mul(y);