[REBASE & FF] Enable Clippy's Deny indexing_slicing Lint#1517
Conversation
✅ QEMU Validation PassedAll QEMU validation jobs completed successfully.
Workflow run: https://github.com/OpenDevicePartnership/patina/actions/runs/26253306380 Boot Time to EFI Shell
Dependencies
This comment was automatically generated by the Patina QEMU PR Validation Post workflow. |
|
Hmm, the clippy logic with all targets is not working correctly because it didn't check all the arm64 code. Will run on an arm64 machine and fix those up; will also take a look at why clippy with all targets isn't working here |
In preparation for enabling the clippy lint to disable direct slice indexing, fix up instances in patina_acpi. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation to enable the clippy lint disallowing direct slice indexing, don't do it in patina_adv_logger. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint disallowing direct slice indexing, don't use it in patina_mm. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint disallowing direct slice indexing, don't use it in patina_performance. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_debugger. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_internal_collections. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_internal_cpu. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_internal_depex. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_stacktrace. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation to enable the clippy lint that disallows direct slice indexing, don't do it in patina_dxe_core. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't use it in the SDK. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_ffs. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_macro. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
In preparation for enabling the clippy lint that disallows direct slice indexing, don't do it in patina_ffs_extractors. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
All code has been updated to not use direct slice indexing or allow it for specific cases. Enable the lint. Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
|
||
| log::debug!(target: "mm_comm", "Outgoing MM communication request: buffer_id={}, data_size={}, recipient={:?}", id, data_buffer.len(), recipient); | ||
| log::debug!(target: "mm_comm", "Request Data (hex): {:02X?}", &data_buffer[..core::cmp::min(data_buffer.len(), 64)]); | ||
| log::debug!(target: "mm_comm", "Request Data (hex): {:02X?}", data_buffer.get(..core::cmp::min(data_buffer.len(), 64)).unwrap_or(data_buffer)); |
There was a problem hiding this comment.
This one seems like slicing is acceptable. I have only started scrolling through this code so I'm not sure if you are making some exceptions with allow(clippy::indexing_slicing)
There was a problem hiding this comment.
My general pattern was to not allow direct slice indexing except for cases where we had to, i.e. const functions. Otherwise, only tests were allowed to have it.
There are a lot of places where it is acceptable because of checks being done, but I tried to have migrate to using .get() and dropping the redundant checks in the code. This reduces the number of allows required and then also the .get() stays with the slice if you move logic around, but you may accidentally move the slice indexing before the check and blow up, etc.
So, I'm not opposed to allow direct slice indexing some places, but I do think we should be judicious in where we choose to. I would prefer to have a reason to allow it, i.e. perf, instead of having a reason to not use it.
For this case, it's a debug print that isn't compiled in most of the time, I'd just leave .get and say, yeah, it's a little silly it does .get() on a min of the buffer len, but who cares. But I don't have a strong feeling on it.
| let rec_len = header.length as usize; | ||
| if rec_len < PerformanceRecordHeader::SIZE { | ||
| self.bytes = &self.bytes[PerformanceRecordHeader::SIZE..]; | ||
| self.bytes = self.bytes.get(PerformanceRecordHeader::SIZE..).unwrap_or(&[]); |
There was a problem hiding this comment.
I'm wondering if its better to leave self.bytes untouched if we cannot get the bytes. something like
if rec_len < PerformanceRecordHeader::SIZE
and let Some(bytes) = self.bytes.get(PerformanceRecordHeader::SIZE..)
{
self.bytes = bytes;
}| node.set_right(Some(next)); | ||
| next.set_left(Some(node)); | ||
| node = next; | ||
| for pair in buffer.windows(2) { |
There was a problem hiding this comment.
I think this is cleaner:
for [node, next] in buffer.array_windows::<2>() {
node.set_right(Some(next));
next.set_left(Some(node));
}| Self::build_linked_list(self.data); | ||
| self.available.set(self.data[0].as_mut_ptr()); | ||
| // first() is safe: we just assigned a non-empty buffer (assert above ensures len >= capacity). | ||
| self.available.set(self.data.first().expect("non-empty buffer").as_mut_ptr()); |
There was a problem hiding this comment.
This one seems unnecessary and results in a safety check followed by an unwrap uncheck. The performance difference is minimal but still not sure if this helps anything at all.
| } | ||
|
|
||
| let Err(idx) = self.search(elements[0]) else { | ||
| let first = *elements.first().ok_or(Error::NotSorted)?; |
There was a problem hiding this comment.
These new deref's make me nervous as to if we are copying or dereferencing.
| @@ -123,18 +124,28 @@ where | |||
| /// | |||
| /// Returns the exact datum if it exists, or the closest datum that is greater than the key if it does not. | |||
| pub fn search_with_key(&self, key: &T::Key) -> Result<&T, &T> { | |||
There was a problem hiding this comment.
to keep the immutable and mutable functions almost the same, maybe we do something like below. the self.is_empty() assert should make sure you can index without using get() you could still use get and "expect" if you wanted, to provide a better error message. Otherwise, we need to change the interface for this function IMO.
pub fn search_with_key(&self, key: &T::Key) -> Result<&T, &T> {
assert!(!self.is_empty());
match self.binary_search_by_key(key, |e| e.key()) {
Ok(idx) => Ok(&self[idx]),
Err(idx) => {
// Clamp to last valid index when binary_search returns past-the-end.
let idx = idx.min(self.len().saturating_sub(1));
Err(&self[idx])
}
}
}
pub fn search_with_key_mut(&mut self, key: &T::Key) -> Result<&mut T, &mut T> {
match self.binary_search_by_key(key, |e| e.key()) {
Ok(idx) => Ok(&mut self[idx]),
Err(idx) => {
// Clamp to last valid index when binary_search returns past-the-end.
let idx = idx.min(self.len().saturating_sub(1));
Err(&mut self[idx])
}
}
}| if let Some(dest) = self.buffer.get_mut(self.pos..self.pos + len) { | ||
| dest.copy_from_slice(data); | ||
| } | ||
| self.pos += len; |
There was a problem hiding this comment.
It seems like something more should be done if the copy cannot be performed than just bump self.pos.
| if let Some(dest) = self.buffer.get_mut(self.buffer_size..self.buffer_size + len) { | ||
| dest.copy_from_slice(data); | ||
| } | ||
| self.buffer_size += len; |
There was a problem hiding this comment.
Similar to the case in monitor.rs, it seems strange to keep incrementing self.buffer_size here if the copy was not possible.
| if let Some(slot) = self.values.get_mut(index) { | ||
| *slot = Some(value); | ||
| } |
There was a problem hiding this comment.
This code is a little more verbose/less readable. It seems like the resize_with() call should catch any practical problems. Is that your understanding?
| @@ -293,7 +293,7 @@ impl Registers for X64CoreRegs { | |||
| return Err(()); | |||
| } | |||
| let mut array = [0u8; core::mem::size_of::<$t>()]; | |||
There was a problem hiding this comment.
Can this follow what was done for the read!() macro in core\patina_debugger\src\arch\aarch64.rs?
| } | ||
|
|
||
| #[cfg(test)] | ||
| #[allow(clippy::indexing_slicing)] |
There was a problem hiding this comment.
I believe you can put this in a clippy.toml so that you don't need to do this on all the tests:
# Workspace clippy.toml
allow-indexing-slicing-in-tests = true
Description
This enables an optional clippy lint to disallow direct slice indexing. First, all instances in the codebase are fixed or explicitly allowed.
The only places they are explicitly allowed are:
Each crate was updated separately to make any future bisects easier to identify where an issue occurred and to allow reviewers to focus on crates they care about.
How This Was Tested
Unit tests, booting to Win/Linux on Q35/SBSA and Windows on a physical Intel platform.
Integration Instructions
Clippy will now fail when direct slice indexing is used. Developers must either use .get() (preferred) or disable the lint at the smallest level possible if it is not possible to use .get().