Skip to content

Commit 2f650aa

Browse files
committed
fix discriminant getting skipped
1 parent 1e1f8c1 commit 2f650aa

3 files changed

Lines changed: 110 additions & 6 deletions

File tree

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
309309
/// These bytes contain data for at least one valid value, but are padding for at least one
310310
/// other valid value. In other words, whether such a byte is initialized depends on the
311311
/// concrete value, hence "value-dependent". This is exactly the padding that is *not*
312-
/// already returned by [`Self::guaranteed_padding_ranges`].
312+
/// already returned by [`Self::variant_independent_padding_ranges`].
313313
///
314314
/// For example, `Option<i8>` has no guaranteed padding, but the byte holding the payload is
315315
/// value-dependent padding: it is data for `Some(_)` and padding for `None`.
@@ -374,6 +374,16 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
374374
}
375375
},
376376
Variants::Multiple { variants, .. } => {
377+
// The variants do not contain e.g. the discriminant or coroutine upvars.
378+
let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else {
379+
unreachable!("a multi-variant layout should have `Arbitrary` fields")
380+
};
381+
382+
for (field, &offset) in offsets.iter_enumerated() {
383+
let field = self.field(cx, field.as_usize());
384+
field.add_data_ranges(cx, base_offset + offset, out);
385+
}
386+
377387
for variant in variants.indices() {
378388
let variant = self.for_variant(cx, variant);
379389
variant.add_data_ranges(cx, base_offset, out);
@@ -441,14 +451,31 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
441451
}
442452
},
443453
Variants::Multiple { variants, .. } => {
444-
// A byte is data for every value only when it is data for every value of every
445-
// variant.
446-
out = variants
454+
// The variants do not contain e.g. the discriminant or coroutine upvars.
455+
let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else {
456+
unreachable!("a multi-variant layout should have `Arbitrary` fields")
457+
};
458+
459+
// The fields are variant-independent and always data.
460+
for (field, &offset) in offsets.iter_enumerated() {
461+
let field = self.field(cx, field.as_usize());
462+
let field = field.always_data_ranges(cx, base_offset + offset);
463+
for &(offset, size) in field.0.iter() {
464+
out.add_range(offset, size);
465+
}
466+
}
467+
468+
// Otherwise a byte is data for every value only when it is data for every variant.
469+
if let Some(common) = variants
447470
.indices()
448471
.map(|variant| self.for_variant(cx, variant))
449472
.map(|variant| variant.always_data_ranges(cx, base_offset))
450473
.reduce(|acc, f| acc.intersection(&f))
451-
.unwrap_or(out);
474+
{
475+
for &(offset, size) in common.0.iter() {
476+
out.add_range(offset, size);
477+
}
478+
}
452479
}
453480
}
454481

compiler/rustc_lint/src/cmse_uninitialized_leak.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ declare_lint! {
3737
/// return values that cross the secure boundary can contain stale secure data in their
3838
/// padding bytes.
3939
///
40-
/// The compiler zeroes all variant-independent padding: bytes that are padding for all valid
40+
/// The compiler clears all variant-independent padding: bytes that are padding for all valid
4141
/// values of the type. But enum and union values can contain variant-dependent padding: bytes
4242
/// that are padding for some but not all valid values of the type. For instance, `Option<u8>`
4343
/// has no padding when `Some(_)` but does have padding when `None`.

tests/assembly-llvm/cmse-clear-padding.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,80 @@ extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit_tuple(
202202
) -> (MaybeUninit<WideU8>, MaybeUninit<WideU8>) {
203203
unsafe { (mem::transmute(a), mem::transmute(b)) }
204204
}
205+
206+
// Check that the tag does not get cleared.
207+
enum Enum {
208+
A(u16),
209+
B(u16),
210+
}
211+
212+
// CHECK-LABEL: cmse_ret_enum:
213+
// CHECK: .fnstart
214+
// CHECK-NEXT: .save {r7, lr}
215+
// CHECK-NEXT: push {r7, lr}
216+
// CHECK-NEXT: .setfp r7, sp
217+
// CHECK-NEXT: mov r7, sp
218+
// CHECK-NEXT: pop.w {r7, lr}
219+
// CHECK-NEXT: mov r1, lr
220+
// CHECK-NEXT: mov r2, lr
221+
// CHECK-NEXT: mov r3, lr
222+
// CHECK-NEXT: mov r12, lr
223+
// CHECK-NEXT: msr apsr_nzcvq, lr
224+
// CHECK-NEXT: bxns lr
225+
#[no_mangle]
226+
extern "cmse-nonsecure-entry" fn cmse_ret_enum(x: Enum) -> Enum {
227+
x
228+
}
229+
230+
// Check that variant-dependent padding is left alone.
231+
enum VariantPadding {
232+
A(u8),
233+
B(u16),
234+
}
235+
236+
// CHECK-LABEL: cmse_ret_enum_with_variant_padding:
237+
// CHECK: .fnstart
238+
// CHECK-NEXT: .save {r7, lr}
239+
// CHECK-NEXT: push {r7, lr}
240+
// CHECK-NEXT: .setfp r7, sp
241+
// CHECK-NEXT: mov r7, sp
242+
// CHECK-NEXT: pop.w {r7, lr}
243+
// CHECK-NEXT: mov r1, lr
244+
// CHECK-NEXT: mov r2, lr
245+
// CHECK-NEXT: mov r3, lr
246+
// CHECK-NEXT: mov r12, lr
247+
// CHECK-NEXT: msr apsr_nzcvq, lr
248+
// CHECK-NEXT: bxns lr
249+
#[no_mangle]
250+
extern "cmse-nonsecure-entry" fn cmse_ret_enum_with_variant_padding(
251+
x: VariantPadding,
252+
) -> VariantPadding {
253+
x
254+
}
255+
256+
// Check that variant-independent padding does get cleared.
257+
enum IndependentPadding {
258+
A(WideU8),
259+
B(WideU8),
260+
}
261+
262+
// CHECK-LABEL: cmse_ret_enum_with_independent_padding:
263+
// CHECK: .fnstart
264+
// CHECK-NEXT: .save {r7, lr}
265+
// CHECK-NEXT: push {r7, lr}
266+
// CHECK-NEXT: .setfp r7, sp
267+
// CHECK-NEXT: mov r7, sp
268+
// CHECK-NEXT: bic r0, r0, #-16777216
269+
// CHECK-NEXT: pop.w {r7, lr}
270+
// CHECK-NEXT: mov r1, lr
271+
// CHECK-NEXT: mov r2, lr
272+
// CHECK-NEXT: mov r3, lr
273+
// CHECK-NEXT: mov r12, lr
274+
// CHECK-NEXT: msr apsr_nzcvq, lr
275+
// CHECK-NEXT: bxns lr
276+
#[no_mangle]
277+
extern "cmse-nonsecure-entry" fn cmse_ret_enum_with_independent_padding(
278+
x: IndependentPadding,
279+
) -> IndependentPadding {
280+
x
281+
}

0 commit comments

Comments
 (0)