-
Notifications
You must be signed in to change notification settings - Fork 592
array_to_bounded_vec is dangerous #9854
Description
This is utils::arrays::array_to_bounded_vec, which is used throughout the kernel data builders:
pub fn array_to_bounded_vec<T, let N: u32>(array: [T; N]) -> BoundedVec<T, N>
where
T: Empty + Eq,
{
let mut len = 0;
for elem in array {
if !is_empty(elem) {
len += 1;
}
}
BoundedVec { storage: array, len }
}Note how array is not mutated at all: the implementation assumes that all empty values are located at the end of the array, and attempts to only count the non-empty ones. This is extremely dangerous for two reasons:
a) if array were to have even a single empty value with a lower index than any non-empty value, the non-empty value would be lost, and BoundedVec's storage would be corrupt
b) if T::empty() returns true for any value that is not std::mem::zeroed(), BoundedVec's storage will again be corrupt. This is because BoundedVec assumes that unused storage elements are cleared, and blindly compares all of storage in its eq implementation. An empty value that is not zeroed would cause for the resulting BoundedVec to not be equal to one that is created by inserting all of its elements into a new one, since the 'empty' storage would not be the same.
Additionally, array_to_bounded_vec does not convey this handling of empty values, and seems to imply the function would behave the same as BoundedVec::from_array, which it does not.
I stumbled upon this when clearing warnings: this function emits some as BoundedVec's storage and len properties are private as they are not meant to be directly accessed (due to issues like the ones described here).