mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
rust: devres: fix leaking call to devm_add_action()
When the data argument of Devres::new() is Err(), we leak the preceding
call to devm_add_action().
In order to fix this, call devm_add_action() in a unit type initializer in
try_pin_init!() after the initializers of all other fields.
Fixes: f5d3ef25d2
("rust: devres: get rid of Devres' inner Arc")
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://lore.kernel.org/r/20250812130928.11075-1-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
parent
a5ba9ad417
commit
75a7b151e8
@ -115,10 +115,11 @@ pub struct Devres<T: Send> {
|
||||
/// Contains all the fields shared with [`Self::callback`].
|
||||
// TODO: Replace with `UnsafePinned`, once available.
|
||||
//
|
||||
// Subsequently, the `drop_in_place()` in `Devres::drop` and the explicit `Send` and `Sync'
|
||||
// impls can be removed.
|
||||
// Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the
|
||||
// explicit `Send` and `Sync' impls can be removed.
|
||||
#[pin]
|
||||
inner: Opaque<Inner<T>>,
|
||||
_add_action: (),
|
||||
}
|
||||
|
||||
impl<T: Send> Devres<T> {
|
||||
@ -140,7 +141,15 @@ impl<T: Send> Devres<T> {
|
||||
dev: dev.into(),
|
||||
callback,
|
||||
// INVARIANT: `inner` is properly initialized.
|
||||
inner <- {
|
||||
inner <- Opaque::pin_init(try_pin_init!(Inner {
|
||||
devm <- Completion::new(),
|
||||
revoke <- Completion::new(),
|
||||
data <- Revocable::new(data),
|
||||
})),
|
||||
// TODO: Replace with "initializer code blocks" [1] once available.
|
||||
//
|
||||
// [1] https://github.com/Rust-for-Linux/pin-init/pull/69
|
||||
_add_action: {
|
||||
// SAFETY: `this` is a valid pointer to uninitialized memory.
|
||||
let inner = unsafe { &raw mut (*this.as_ptr()).inner };
|
||||
|
||||
@ -152,13 +161,13 @@ impl<T: Send> Devres<T> {
|
||||
// live at least as long as the returned `impl PinInit<Self, Error>`.
|
||||
to_result(unsafe {
|
||||
bindings::devm_add_action(dev.as_raw(), Some(callback), inner.cast())
|
||||
})?;
|
||||
}).inspect_err(|_| {
|
||||
let inner = Opaque::cast_into(inner);
|
||||
|
||||
Opaque::pin_init(try_pin_init!(Inner {
|
||||
devm <- Completion::new(),
|
||||
revoke <- Completion::new(),
|
||||
data <- Revocable::new(data),
|
||||
}))
|
||||
// SAFETY: `inner` is a valid pointer to an `Inner<T>` and valid for both reads
|
||||
// and writes.
|
||||
unsafe { core::ptr::drop_in_place(inner) };
|
||||
})?;
|
||||
},
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user