History

rust: enable `clippy::undocumented_unsafe_blocks` lint

Checking that we are not missing any `// SAFETY` comments in our `unsafe` blocks is something we have wanted to do for a long time, as well as cleaning up the remaining cases that were not documented [1]. Back when Rust for Linux started, this was something that could have been done via a script, like Rust's `tidy`. Soon after, in Rust 1.58.0, Clippy implemented the `undocumented_unsafe_blocks` lint [2]. Even though the lint has a few false positives, e.g. in some cases where attributes appear between the comment and the `unsafe` block [3], there are workarounds and the lint seems quite usable already. Thus enable the lint now. We still have a few cases to clean up, so just allow those for the moment by writing a `TODO` comment -- some of those may be good candidates for new contributors.

Miguel Ojeda committed 2 years ago

Commit db4f72c1 parent 567cdff16 files · +47 −10Browse files

Unified · Split

16 files
  1. Makefile +1 −0
  2. mm/kasan/kasan_test_rust.rs +1 −0
  3. rust/bindings/lib.rs +1 −0
  4. rust/kernel/alloc/allocator.rs +2 −0
  5. rust/kernel/error.rs +6 −3
  6. rust/kernel/init.rs +5 −0
  7. rust/kernel/init/__internal.rs +2 −0
  8. rust/kernel/init/macros.rs +9 −0
  9. rust/kernel/list.rs +1 −0
  10. rust/kernel/print.rs +2 −0
  11. rust/kernel/str.rs +4 −3
  12. rust/kernel/sync/condvar.rs +1 −1
  13. rust/kernel/sync/lock.rs +3 −3
  14. rust/kernel/types.rs +4 −0
  15. rust/kernel/workqueue.rs +4 −0
  16. rust/uapi/lib.rs +1 −0
Makefile+1−0
@@ -457,6 +457,7 @@ export rust_common_flags := --edition=2021 \ · 456 unmodified lines
457457 -Wclippy::needless_bitwise_bool \
458458 -Wclippy::needless_continue \
459459 -Wclippy::no_mangle_with_rust_abi \
460+ -Wclippy::undocumented_unsafe_blocks \
460461 -Wrustdoc::missing_crate_level_docs
461462
462463 KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
mm/kasan/kasan_test_rust.rs+1−0
@@ -17,5 +17,6 @@ pub extern "C" fn kasan_test_rust_uaf() -> u8 { · 16 unmodified lines
1717 }
1818 let ptr: *mut u8 = addr_of_mut!(v[2048]);
1919 drop(v);
20+ // SAFETY: Incorrect, on purpose.
2021 unsafe { *ptr }
2122 }
rust/bindings/lib.rs+1−0
@@ -25,6 +25,7 @@ · 24 unmodified lines
2525 )]
2626
2727 #[allow(dead_code)]
28+#[allow(clippy::undocumented_unsafe_blocks)]
2829 mod bindings_raw {
2930 // Use glob import here to expose all helpers.
3031 // Symbols defined within the module will take precedence to the glob import.
rust/kernel/alloc/allocator.rs+2−0
@@ -31,6 +31,7 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F · 30 unmodified lines
3131 unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 }
3232 }
3333
34+// SAFETY: TODO.
3435 unsafe impl GlobalAlloc for KernelAllocator {
3536 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
3637 // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
@@ -39,6 +40,7 @@ unsafe impl GlobalAlloc for KernelAllocator { · 2 unmodified lines
3940 }
4041
4142 unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
43+ // SAFETY: TODO.
4244 unsafe {
4345 bindings::kfree(ptr as *const core::ffi::c_void);
4446 }
rust/kernel/error.rs+6−3
@@ -171,9 +171,11 @@ impl fmt::Debug for Error { · 170 unmodified lines
171171 match self.name() {
172172 // Print out number if no name can be found.
173173 None => f.debug_tuple("Error").field(&-self.0).finish(),
174− // SAFETY: These strings are ASCII-only.
175174 Some(name) => f
176− .debug_tuple(unsafe { core::str::from_utf8_unchecked(name) })
175+ .debug_tuple(
176+ // SAFETY: These strings are ASCII-only.
177+ unsafe { core::str::from_utf8_unchecked(name) },
178+ )
177179 .finish(),
178180 }
179181 }
@@ -277,6 +279,8 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { · 97 unmodified lines
277279 if unsafe { bindings::IS_ERR(const_ptr) } {
278280 // SAFETY: The FFI function does not deref the pointer.
279281 let err = unsafe { bindings::PTR_ERR(const_ptr) };
282+
283+ #[allow(clippy::unnecessary_cast)]
280284 // CAST: If `IS_ERR()` returns `true`,
281285 // then `PTR_ERR()` is guaranteed to return a
282286 // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
@@ -286,7 +290,6 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { · 3 unmodified lines
286290 //
287291 // SAFETY: `IS_ERR()` ensures `err` is a
288292 // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
289− #[allow(clippy::unnecessary_cast)]
290293 return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) });
291294 }
292295 Ok(ptr)
rust/kernel/init.rs+5−0
@@ -541,6 +541,7 @@ macro_rules! stack_try_pin_init { · 540 unmodified lines
541541 /// }
542542 /// pin_init!(&this in Buf {
543543 /// buf: [0; 64],
544+/// // SAFETY: TODO.
544545 /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
545546 /// pin: PhantomPinned,
546547 /// });
@@ -875,6 +876,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { · 328 unmodified lines
875876 /// }
876877 ///
877878 /// let foo = pin_init!(Foo {
879+ /// // SAFETY: TODO.
878880 /// raw <- unsafe {
879881 /// Opaque::ffi_init(|s| {
880882 /// init_foo(s);
@@ -1162,6 +1164,7 @@ where · 281 unmodified lines
11621164 // SAFETY: Every type can be initialized by-value.
11631165 unsafe impl<T, E> Init<T, E> for T {
11641166 unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
1167+ // SAFETY: TODO.
11651168 unsafe { slot.write(self) };
11661169 Ok(())
11671170 }
@@ -1170,6 +1173,7 @@ unsafe impl<T, E> Init<T, E> for T { · 2 unmodified lines
11701173 // SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`.
11711174 unsafe impl<T, E> PinInit<T, E> for T {
11721175 unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
1176+ // SAFETY: TODO.
11731177 unsafe { self.__init(slot) }
11741178 }
11751179 }
@@ -1411,6 +1415,7 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> { · 235 unmodified lines
14111415
14121416 macro_rules! impl_zeroable {
14131417 ($($({$($generics:tt)*})? $t:ty, )*) => {
1418+ // SAFETY: Safety comments written in the macro invocation.
14141419 $(unsafe impl$($($generics)*)? Zeroable for $t {})*
14151420 };
14161421 }
rust/kernel/init/__internal.rs+2−0
@@ -112,10 +112,12 @@ impl<T: ?Sized> Clone for AllData<T> { · 111 unmodified lines
112112
113113 impl<T: ?Sized> Copy for AllData<T> {}
114114
115+// SAFETY: TODO.
115116 unsafe impl<T: ?Sized> InitData for AllData<T> {
116117 type Datee = T;
117118 }
118119
120+// SAFETY: TODO.
119121 unsafe impl<T: ?Sized> HasInitData for T {
120122 type InitData = AllData<T>;
121123
rust/kernel/init/macros.rs+9−0
@@ -513,6 +513,7 @@ macro_rules! __pinned_drop { · 512 unmodified lines
513513 }
514514 ),
515515 ) => {
516+ // SAFETY: TODO.
516517 unsafe $($impl_sig)* {
517518 // Inherit all attributes and the type/ident tokens for the signature.
518519 $(#[$($attr)*])*
@@ -872,6 +873,7 @@ macro_rules! __pin_data { · 353 unmodified lines
872873 }
873874 }
874875
876+ // SAFETY: TODO.
875877 unsafe impl<$($impl_generics)*>
876878 $crate::init::__internal::PinData for __ThePinData<$($ty_generics)*>
877879 where $($whr)*
@@ -997,6 +999,7 @@ macro_rules! __pin_data { · 119 unmodified lines
997999 slot: *mut $p_type,
9981000 init: impl $crate::init::PinInit<$p_type, E>,
9991001 ) -> ::core::result::Result<(), E> {
1002+ // SAFETY: TODO.
10001003 unsafe { $crate::init::PinInit::__pinned_init(init, slot) }
10011004 }
10021005 )*
@@ -1007,6 +1010,7 @@ macro_rules! __pin_data { · 4 unmodified lines
10071010 slot: *mut $type,
10081011 init: impl $crate::init::Init<$type, E>,
10091012 ) -> ::core::result::Result<(), E> {
1013+ // SAFETY: TODO.
10101014 unsafe { $crate::init::Init::__init(init, slot) }
10111015 }
10121016 )*
@@ -1121,6 +1125,8 @@ macro_rules! __init_internal { · 108 unmodified lines
11211125 // no possibility of returning without `unsafe`.
11221126 struct __InitOk;
11231127 // Get the data about fields from the supplied type.
1128+ //
1129+ // SAFETY: TODO.
11241130 let data = unsafe {
11251131 use $crate::init::__internal::$has_data;
11261132 // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal
@@ -1176,6 +1182,7 @@ macro_rules! __init_internal { · 49 unmodified lines
11761182 let init = move |slot| -> ::core::result::Result<(), $err> {
11771183 init(slot).map(|__InitOk| ())
11781184 };
1185+ // SAFETY: TODO.
11791186 let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) };
11801187 init
11811188 }};
@@ -1324,6 +1331,8 @@ macro_rules! __init_internal { · 142 unmodified lines
13241331 // Endpoint, nothing more to munch, create the initializer.
13251332 // Since we are in the closure that is never called, this will never get executed.
13261333 // We abuse `slot` to get the correct type inference here:
1334+ //
1335+ // SAFETY: TODO.
13271336 unsafe {
13281337 // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal
13291338 // information that is associated to already parsed fragments, so a path fragment
rust/kernel/list.rs+1−0
@@ -354,6 +354,7 @@ impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> { · 353 unmodified lines
354354 ///
355355 /// `item` must not be in a different linked list (with the same id).
356356 pub unsafe fn remove(&mut self, item: &T) -> Option<ListArc<T, ID>> {
357+ // SAFETY: TODO.
357358 let mut item = unsafe { ListLinks::fields(T::view_links(item)) };
358359 // SAFETY: The user provided a reference, and reference are never dangling.
359360 //
rust/kernel/print.rs+2−0
@@ -23,6 +23,7 @@ unsafe extern "C" fn rust_fmt_argument( · 22 unmodified lines
2323 use fmt::Write;
2424 // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
2525 let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
26+ // SAFETY: TODO.
2627 let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
2728 w.pos().cast()
2829 }
@@ -102,6 +103,7 @@ pub unsafe fn call_printk( · 73 unmodified lines
102103 ) {
103104 // `_printk` does not seem to fail in any path.
104105 #[cfg(CONFIG_PRINTK)]
106+ // SAFETY: TODO.
105107 unsafe {
106108 bindings::_printk(
107109 format_string.as_ptr() as _,
rust/kernel/str.rs+4−3
@@ -162,10 +162,10 @@ impl CStr { · 161 unmodified lines
162162 /// Returns the length of this string with `NUL`.
163163 #[inline]
164164 pub const fn len_with_nul(&self) -> usize {
165− // SAFETY: This is one of the invariant of `CStr`.
166− // We add a `unreachable_unchecked` here to hint the optimizer that
167− // the value returned from this function is non-zero.
168165 if self.0.is_empty() {
166+ // SAFETY: This is one of the invariant of `CStr`.
167+ // We add a `unreachable_unchecked` here to hint the optimizer that
168+ // the value returned from this function is non-zero.
169169 unsafe { core::hint::unreachable_unchecked() };
170170 }
171171 self.0.len()
@@ -301,6 +301,7 @@ impl CStr { · 129 unmodified lines
301301 /// ```
302302 #[inline]
303303 pub unsafe fn as_str_unchecked(&self) -> &str {
304+ // SAFETY: TODO.
304305 unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
305306 }
306307
rust/kernel/sync/condvar.rs+1−1
@@ -92,8 +92,8 @@ pub struct CondVar { · 91 unmodified lines
9292 _pin: PhantomPinned,
9393 }
9494
95−// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread.
9695 #[allow(clippy::non_send_fields_in_send_ty)]
96+// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread.
9797 unsafe impl Send for CondVar {}
9898
9999 // SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads
rust/kernel/sync/lock.rs+3−3
@@ -150,9 +150,9 @@ impl<T: ?Sized, B: Backend> Guard<'_, T, B> { · 149 unmodified lines
150150 // SAFETY: The caller owns the lock, so it is safe to unlock it.
151151 unsafe { B::unlock(self.lock.state.get(), &self.state) };
152152
153− // SAFETY: The lock was just unlocked above and is being relocked now.
154− let _relock =
155− ScopeGuard::new(|| unsafe { B::relock(self.lock.state.get(), &mut self.state) });
153+ let _relock = ScopeGuard::new(||
154+ // SAFETY: The lock was just unlocked above and is being relocked now.
155+ unsafe { B::relock(self.lock.state.get(), &mut self.state) });
156156
157157 cb()
158158 }
rust/kernel/types.rs+4−0
@@ -410,6 +410,7 @@ impl<T: AlwaysRefCounted> ARef<T> { · 409 unmodified lines
410410 ///
411411 /// struct Empty {}
412412 ///
413+ /// # // SAFETY: TODO.
413414 /// unsafe impl AlwaysRefCounted for Empty {
414415 /// fn inc_ref(&self) {}
415416 /// unsafe fn dec_ref(_obj: NonNull<Self>) {}
@@ -417,6 +418,7 @@ impl<T: AlwaysRefCounted> ARef<T> { · 1 unmodified line
417418 ///
418419 /// let mut data = Empty {};
419420 /// let ptr = NonNull::<Empty>::new(&mut data as *mut _).unwrap();
421+ /// # // SAFETY: TODO.
420422 /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
421423 /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);
422424 ///
@@ -492,6 +494,7 @@ pub unsafe trait FromBytes {} · 69 unmodified lines
492494
493495 macro_rules! impl_frombytes {
494496 ($($({$($generics:tt)*})? $t:ty, )*) => {
497+ // SAFETY: Safety comments written in the macro invocation.
495498 $(unsafe impl$($($generics)*)? FromBytes for $t {})*
496499 };
497500 }
@@ -526,6 +529,7 @@ pub unsafe trait AsBytes {} · 28 unmodified lines
526529
527530 macro_rules! impl_asbytes {
528531 ($($({$($generics:tt)*})? $t:ty, )*) => {
532+ // SAFETY: Safety comments written in the macro invocation.
529533 $(unsafe impl$($($generics)*)? AsBytes for $t {})*
530534 };
531535 }
rust/kernel/workqueue.rs+4−0
@@ -519,6 +519,7 @@ impl_has_work! { · 518 unmodified lines
519519 impl{T} HasWork<Self> for ClosureWork<T> { self.work }
520520 }
521521
522+// SAFETY: TODO.
522523 unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T>
523524 where
524525 T: WorkItem<ID, Pointer = Self>,
@@ -536,6 +537,7 @@ where · 11 unmodified lines
536537 }
537538 }
538539
540+// SAFETY: TODO.
539541 unsafe impl<T, const ID: u64> RawWorkItem<ID> for Arc<T>
540542 where
541543 T: WorkItem<ID, Pointer = Self>,
@@ -564,6 +566,7 @@ where · 22 unmodified lines
564566 }
565567 }
566568
569+// SAFETY: TODO.
567570 unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>>
568571 where
569572 T: WorkItem<ID, Pointer = Self>,
@@ -583,6 +586,7 @@ where · 13 unmodified lines
583586 }
584587 }
585588
589+// SAFETY: TODO.
586590 unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<Box<T>>
587591 where
588592 T: WorkItem<ID, Pointer = Self>,
rust/uapi/lib.rs+1−0
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
1515 #![allow(
1616 clippy::all,
17+ clippy::undocumented_unsafe_blocks,
1718 dead_code,
1819 missing_docs,
1920 non_camel_case_types,