Unused return enum
Description
- Issue Category:
Validations and error handling - Issue Severity:
Minor - Detectors:
unused-return-enum - Test Cases:
unused-return-enum-1unused-return-enum-2
Soroban messages can return a Result enum with a custom error type. This is useful for the caller to know what went wrong when the message fails.
The definition in Rust of the Result enum is:
enum Result<T, E> {
Ok(T),
Err(E),
}
Why is this bad?
If either variant (Ok or Err) is not used in the code, it could indicate that the Result type is unnecessary and that the code could be simplified. Alternatively, it might suggest a bug where a possible outcome is not being handled properly.
Issue example
Consider the following Soroban contract:
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Error {
/// An overflow was produced.
Overflow = 1,
}
pub fn get_percentage_difference(balance1: u128, balance2: u128) -> Result<u128, Error> {
let absolute_difference = balance1.abs_diff(balance2);
let sum = balance1 + balance2;
match 100u128.checked_mul(absolute_difference / sum) {
Some(result) => result,
None => panic!("Overflow"),
};
Err(Error::Overflow)
}
This is a Soroban message that returns the percentage difference between two values.
The function then returns an error enum variant TradingPairErrors::Overflow.
However, the function never returns a Result enum variant Ok, thus always
failing.
The vulnerable code example can be found here.
Remediated example
This function could be easily fixed by returning a Result enum variant Ok
when the percentage difference is calculated successfully. By providing a check in
the linter that ensures that all the variants of the Result enum are used, this
bug could have been avoided. This is shown in the example below:
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Error {
/// An overflow was produced.
Overflow = 1,
}
pub fn get_percentage_difference(balance1: u128, balance2: u128) -> Result<u128, Error> {
let absolute_difference = balance1.abs_diff(balance2);
let sum = balance1 + balance2;
match 100u128.checked_mul(absolute_difference / sum) {
Some(result) => Ok(result),
None => Err(Error::Overflow),
}
}
The remediated code example can be found here.
How is it detected?
It warns if a function that returns a Result type does not return the Result enum variant (Ok/Err).