Skip to main content

Iterators over indexing

Description​

In Rust, sequences can be traversed using iterators or direct indexing. However, the least efficient way is through direct indexing.

Why is this bad?​

When you iterate over a data structure with fixed limits in a Soroban smart contract, exceeding those limits can cause the contract to panic, potentially leading to errors or unexpected behavior.

Issue example​

Consider the following Soroban contract:

   pub fn sum(e: Env) -> Result<i32, Error> {
let mut ret = 0_i32;
let vec = e
.storage()
.instance()
.get::<DataKey, Vec<i32>>(&DataKey::Data)
.ok_or(Error::NoData)?;
for i in 0..4 {
ret = ret
.checked_add(vec.get(i).ok_or(Error::NoData)?)
.ok_or(Error::IntegerOverflow)?;
}
Ok(ret)
}

The problem arises in the for loop. If vec has less than 4 elements, the contract will panic.

The code example can be found here.

Remediated example​

     pub fn sum(e: Env) -> Result<i32, Error> {
let mut ret = 0_i32;
let vec = e
.storage()
.instance()
.get::<DataKey, Vec<i32>>(&DataKey::Data)
.ok_or(Error::NoData)?;
for i in vec {
ret = ret.checked_add(i).ok_or(Error::IntegerOverflow)?;
}
Ok(ret)
}

Instead of using a fixed loop, iterate through the vector itself using for i in vec. This ensures the loop iterates only for valid elements present in the vector.

The remediated code example can be found here.

How is it detected?​

It warns if the for loop uses indexing instead of iterator. If the indexing goes to length it will not raise a warning.