Skip to content

Commit e92b287

Browse files
committed
Merge tag 'rust-fixes-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust fixes from Miguel Ojeda: "Toolchain and infrastructure: - Add 'bindgen' target to make UML 32-bit builds work with GCC - Disable two Clippy warnings ('collapsible_{if,match}') 'pin-init' crate: - Fix unsoundness issue that created &'static references" * tag 'rust-fixes-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: rust: allow `clippy::collapsible_if` globally rust: allow `clippy::collapsible_match` globally rust: pin-init: fix incorrect accessor reference lifetime rust: pin-init: internal: move alignment check to `make_field_check` rust: arch: um: Fix building 32-bit UML with GCC
2 parents ec89572 + 2adc866 commit e92b287

5 files changed

Lines changed: 107 additions & 110 deletions

File tree

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ export rust_common_flags := --edition=2021 \
486486
-Wclippy::as_ptr_cast_mut \
487487
-Wclippy::as_underscore \
488488
-Wclippy::cast_lossless \
489+
-Aclippy::collapsible_if \
490+
-Aclippy::collapsible_match \
489491
-Wclippy::ignored_unit_patterns \
490492
-Aclippy::incompatible_msrv \
491493
-Wclippy::mut_mut \

drivers/android/binder/range_alloc/array.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ impl<T> ArrayRangeAllocator<T> {
204204
// caller will mark them as unused, which means that they can be freed if the system comes
205205
// under memory pressure.
206206
let mut freed_range = FreedRange::interior_pages(offset, size);
207-
#[expect(clippy::collapsible_if)] // reads better like this
208207
if offset % PAGE_SIZE != 0 {
209208
if i == 0 || self.ranges[i - 1].endpoint() <= (offset & PAGE_MASK) {
210209
freed_range.start_page_idx -= 1;

rust/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,8 @@ BINDGEN_TARGET_x86 := x86_64-linux-gnu
403403
BINDGEN_TARGET_arm64 := aarch64-linux-gnu
404404
BINDGEN_TARGET_arm := arm-linux-gnueabi
405405
BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf
406+
# This is only for i386 UM builds, which need the 32-bit target not -m32
407+
BINDGEN_TARGET_i386 := i386-linux-gnu
406408
BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH))
407409
BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH))
408410

rust/pin-init/internal/src/init.rs

Lines changed: 84 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -249,84 +249,45 @@ fn init_fields(
249249
});
250250
// Again span for better diagnostics
251251
let write = quote_spanned!(ident.span()=> ::core::ptr::write);
252-
// NOTE: the field accessor ensures that the initialized field is properly aligned.
253-
// Unaligned fields will cause the compiler to emit E0793. We do not support
254-
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
255-
// `ptr::write` below has the same requirement.
256-
let accessor = if pinned {
257-
let project_ident = format_ident!("__project_{ident}");
258-
quote! {
259-
// SAFETY: TODO
260-
unsafe { #data.#project_ident(&mut (*#slot).#ident) }
261-
}
262-
} else {
263-
quote! {
264-
// SAFETY: TODO
265-
unsafe { &mut (*#slot).#ident }
266-
}
267-
};
268252
quote! {
269253
#(#attrs)*
270254
{
271255
#value_prep
272256
// SAFETY: TODO
273257
unsafe { #write(&raw mut (*#slot).#ident, #value_ident) };
274258
}
275-
#(#cfgs)*
276-
#[allow(unused_variables)]
277-
let #ident = #accessor;
278259
}
279260
}
280261
InitializerKind::Init { ident, value, .. } => {
281262
// Again span for better diagnostics
282263
let init = format_ident!("init", span = value.span());
283-
// NOTE: the field accessor ensures that the initialized field is properly aligned.
284-
// Unaligned fields will cause the compiler to emit E0793. We do not support
285-
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
286-
// `ptr::write` below has the same requirement.
287-
let (value_init, accessor) = if pinned {
288-
let project_ident = format_ident!("__project_{ident}");
289-
(
290-
quote! {
291-
// SAFETY:
292-
// - `slot` is valid, because we are inside of an initializer closure, we
293-
// return when an error/panic occurs.
294-
// - We also use `#data` to require the correct trait (`Init` or `PinInit`)
295-
// for `#ident`.
296-
unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? };
297-
},
298-
quote! {
299-
// SAFETY: TODO
300-
unsafe { #data.#project_ident(&mut (*#slot).#ident) }
301-
},
302-
)
264+
let value_init = if pinned {
265+
quote! {
266+
// SAFETY:
267+
// - `slot` is valid, because we are inside of an initializer closure, we
268+
// return when an error/panic occurs.
269+
// - We also use `#data` to require the correct trait (`Init` or `PinInit`)
270+
// for `#ident`.
271+
unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? };
272+
}
303273
} else {
304-
(
305-
quote! {
306-
// SAFETY: `slot` is valid, because we are inside of an initializer
307-
// closure, we return when an error/panic occurs.
308-
unsafe {
309-
::pin_init::Init::__init(
310-
#init,
311-
&raw mut (*#slot).#ident,
312-
)?
313-
};
314-
},
315-
quote! {
316-
// SAFETY: TODO
317-
unsafe { &mut (*#slot).#ident }
318-
},
319-
)
274+
quote! {
275+
// SAFETY: `slot` is valid, because we are inside of an initializer
276+
// closure, we return when an error/panic occurs.
277+
unsafe {
278+
::pin_init::Init::__init(
279+
#init,
280+
&raw mut (*#slot).#ident,
281+
)?
282+
};
283+
}
320284
};
321285
quote! {
322286
#(#attrs)*
323287
{
324288
let #init = #value;
325289
#value_init
326290
}
327-
#(#cfgs)*
328-
#[allow(unused_variables)]
329-
let #ident = #accessor;
330291
}
331292
}
332293
InitializerKind::Code { block: value, .. } => quote! {
@@ -339,18 +300,41 @@ fn init_fields(
339300
if let Some(ident) = kind.ident() {
340301
// `mixed_site` ensures that the guard is not accessible to the user-controlled code.
341302
let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
303+
304+
// NOTE: The reference is derived from the guard so that it only lives as long as the
305+
// guard does and cannot escape the scope. If it's created via `&mut (*#slot).#ident`
306+
// like the unaligned field guard, it will become effectively `'static`.
307+
let accessor = if pinned {
308+
let project_ident = format_ident!("__project_{ident}");
309+
quote! {
310+
// SAFETY: the initialization is pinned.
311+
unsafe { #data.#project_ident(#guard.let_binding()) }
312+
}
313+
} else {
314+
quote! {
315+
#guard.let_binding()
316+
}
317+
};
318+
342319
res.extend(quote! {
343320
#(#cfgs)*
344-
// Create the drop guard:
321+
// Create the drop guard.
345322
//
346-
// We rely on macro hygiene to make it impossible for users to access this local
347-
// variable.
348-
// SAFETY: We forget the guard later when initialization has succeeded.
349-
let #guard = unsafe {
323+
// SAFETY:
324+
// - `&raw mut (*slot).#ident` is valid.
325+
// - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned.
326+
// - `(*slot).#ident` has been initialized above.
327+
// - We only need the ownership to the pointee back when initialization has
328+
// succeeded, where we `forget` the guard.
329+
let mut #guard = unsafe {
350330
::pin_init::__internal::DropGuard::new(
351331
&raw mut (*slot).#ident
352332
)
353333
};
334+
335+
#(#cfgs)*
336+
#[allow(unused_variables)]
337+
let #ident = #accessor;
354338
});
355339
guards.push(guard);
356340
guard_attrs.push(cfgs);
@@ -367,49 +351,49 @@ fn init_fields(
367351
}
368352
}
369353

370-
/// Generate the check for ensuring that every field has been initialized.
354+
/// Generate the check for ensuring that every field has been initialized and aligned.
371355
fn make_field_check(
372356
fields: &Punctuated<InitializerField, Token![,]>,
373357
init_kind: InitKind,
374358
path: &Path,
375359
) -> TokenStream {
376-
let field_attrs = fields
360+
let field_attrs: Vec<_> = fields
377361
.iter()
378-
.filter_map(|f| f.kind.ident().map(|_| &f.attrs));
379-
let field_name = fields.iter().filter_map(|f| f.kind.ident());
380-
match init_kind {
381-
InitKind::Normal => quote! {
382-
// We use unreachable code to ensure that all fields have been mentioned exactly once,
383-
// this struct initializer will still be type-checked and complain with a very natural
384-
// error message if a field is forgotten/mentioned more than once.
385-
#[allow(unreachable_code, clippy::diverging_sub_expression)]
386-
// SAFETY: this code is never executed.
387-
let _ = || unsafe {
388-
::core::ptr::write(slot, #path {
389-
#(
390-
#(#field_attrs)*
391-
#field_name: ::core::panic!(),
392-
)*
393-
})
394-
};
395-
},
396-
InitKind::Zeroing => quote! {
397-
// We use unreachable code to ensure that all fields have been mentioned at most once.
398-
// Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will
399-
// be zeroed. This struct initializer will still be type-checked and complain with a
400-
// very natural error message if a field is mentioned more than once, or doesn't exist.
401-
#[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)]
402-
// SAFETY: this code is never executed.
403-
let _ = || unsafe {
404-
::core::ptr::write(slot, #path {
405-
#(
406-
#(#field_attrs)*
407-
#field_name: ::core::panic!(),
408-
)*
409-
..::core::mem::zeroed()
410-
})
411-
};
412-
},
362+
.filter_map(|f| f.kind.ident().map(|_| &f.attrs))
363+
.collect();
364+
let field_name: Vec<_> = fields.iter().filter_map(|f| f.kind.ident()).collect();
365+
let zeroing_trailer = match init_kind {
366+
InitKind::Normal => None,
367+
InitKind::Zeroing => Some(quote! {
368+
..::core::mem::zeroed()
369+
}),
370+
};
371+
quote! {
372+
#[allow(unreachable_code, clippy::diverging_sub_expression)]
373+
// We use unreachable code to perform field checks. They're still checked by the compiler.
374+
// SAFETY: this code is never executed.
375+
let _ = || unsafe {
376+
// Create references to ensure that the initialized field is properly aligned.
377+
// Unaligned fields will cause the compiler to emit E0793. We do not support
378+
// unaligned fields since `Init::__init` requires an aligned pointer; the call to
379+
// `ptr::write` for value-initialization case has the same requirement.
380+
#(
381+
#(#field_attrs)*
382+
let _ = &(*slot).#field_name;
383+
)*
384+
385+
// If the zeroing trailer is not present, this checks that all fields have been
386+
// mentioned exactly once. If the zeroing trailer is present, all missing fields will be
387+
// zeroed, so this checks that all fields have been mentioned at most once. The use of
388+
// struct initializer will still generate very natural error messages for any misuse.
389+
::core::ptr::write(slot, #path {
390+
#(
391+
#(#field_attrs)*
392+
#field_name: ::core::panic!(),
393+
)*
394+
#zeroing_trailer
395+
})
396+
};
413397
}
414398
}
415399

rust/pin-init/src/__internal.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,32 +238,42 @@ fn stack_init_reuse() {
238238
/// When a value of this type is dropped, it drops a `T`.
239239
///
240240
/// Can be forgotten to prevent the drop.
241+
///
242+
/// # Invariants
243+
///
244+
/// - `ptr` is valid and properly aligned.
245+
/// - `*ptr` is initialized and owned by this guard.
241246
pub struct DropGuard<T: ?Sized> {
242247
ptr: *mut T,
243248
}
244249

245250
impl<T: ?Sized> DropGuard<T> {
246-
/// Creates a new [`DropGuard<T>`]. It will [`ptr::drop_in_place`] `ptr` when it gets dropped.
251+
/// Creates a drop guard and transfer the ownership of the pointer content.
247252
///
248-
/// # Safety
253+
/// The ownership is only relinguished if the guard is forgotten via [`core::mem::forget`].
249254
///
250-
/// `ptr` must be a valid pointer.
255+
/// # Safety
251256
///
252-
/// It is the callers responsibility that `self` will only get dropped if the pointee of `ptr`:
253-
/// - has not been dropped,
254-
/// - is not accessible by any other means,
255-
/// - will not be dropped by any other means.
257+
/// - `ptr` is valid and properly aligned.
258+
/// - `*ptr` is initialized, and the ownership is transferred to this guard.
256259
#[inline]
257260
pub unsafe fn new(ptr: *mut T) -> Self {
261+
// INVARIANT: By safety requirement.
258262
Self { ptr }
259263
}
264+
265+
/// Create a let binding for accessor use.
266+
#[inline]
267+
pub fn let_binding(&mut self) -> &mut T {
268+
// SAFETY: Per type invariant.
269+
unsafe { &mut *self.ptr }
270+
}
260271
}
261272

262273
impl<T: ?Sized> Drop for DropGuard<T> {
263274
#[inline]
264275
fn drop(&mut self) {
265-
// SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function
266-
// ensuring that this operation is safe.
276+
// SAFETY: `self.ptr` is valid, properly aligned and `*self.ptr` is owned by this guard.
267277
unsafe { ptr::drop_in_place(self.ptr) }
268278
}
269279
}

0 commit comments

Comments
 (0)