Skip to content

Commit 75a7b15

Browse files
author
Danilo Krummrich
committed
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: f5d3ef2 ("rust: devres: get rid of Devres' inner Arc") Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Danilo Krummrich <[email protected]>
1 parent a5ba9ad commit 75a7b15

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

rust/kernel/devres.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ pub struct Devres<T: Send> {
115115
/// Contains all the fields shared with [`Self::callback`].
116116
// TODO: Replace with `UnsafePinned`, once available.
117117
//
118-
// Subsequently, the `drop_in_place()` in `Devres::drop` and the explicit `Send` and `Sync'
119-
// impls can be removed.
118+
// Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the
119+
// explicit `Send` and `Sync' impls can be removed.
120120
#[pin]
121121
inner: Opaque<Inner<T>>,
122+
_add_action: (),
122123
}
123124

124125
impl<T: Send> Devres<T> {
@@ -140,7 +141,15 @@ impl<T: Send> Devres<T> {
140141
dev: dev.into(),
141142
callback,
142143
// INVARIANT: `inner` is properly initialized.
143-
inner <- {
144+
inner <- Opaque::pin_init(try_pin_init!(Inner {
145+
devm <- Completion::new(),
146+
revoke <- Completion::new(),
147+
data <- Revocable::new(data),
148+
})),
149+
// TODO: Replace with "initializer code blocks" [1] once available.
150+
//
151+
// [1] https://github.com/Rust-for-Linux/pin-init/pull/69
152+
_add_action: {
144153
// SAFETY: `this` is a valid pointer to uninitialized memory.
145154
let inner = unsafe { &raw mut (*this.as_ptr()).inner };
146155

@@ -152,13 +161,13 @@ impl<T: Send> Devres<T> {
152161
// live at least as long as the returned `impl PinInit<Self, Error>`.
153162
to_result(unsafe {
154163
bindings::devm_add_action(dev.as_raw(), Some(callback), inner.cast())
155-
})?;
164+
}).inspect_err(|_| {
165+
let inner = Opaque::cast_into(inner);
156166

157-
Opaque::pin_init(try_pin_init!(Inner {
158-
devm <- Completion::new(),
159-
revoke <- Completion::new(),
160-
data <- Revocable::new(data),
161-
}))
167+
// SAFETY: `inner` is a valid pointer to an `Inner<T>` and valid for both reads
168+
// and writes.
169+
unsafe { core::ptr::drop_in_place(inner) };
170+
})?;
162171
},
163172
})
164173
}

0 commit comments

Comments
 (0)