Skip to content

Commit 7488b2b

Browse files
Auto merge of #141759 - 1c3t3a:discriminants-query, r=<try>
Insert checks for enum discriminants when debug assertions are enabled Similar to the existing null-pointer and alignment checks, this checks for valid enum discriminants on creation of enums through unsafe transmutes. Essentially this sanitizes patterns like the following: ```rust let val: MyEnum = unsafe { std::mem::transmute<u32, MyEnum>(42) }; ``` An extension of this check will be done in a follow-up that explicitly sanitizes for extern enum values that come into Rust from e.g. C/C++. This check is similar to Miri's capabilities of checking for valid construction of enum values. This PR is inspired by saethlin@'s PR #104862. Thank you so much for keeping this code up and the detailed comments! I also pair-programmed large parts of this together with vabr-g@. r? `@saethlin`
2 parents c6a9554 + 5587fd7 commit 7488b2b

38 files changed

+1008
-3
lines changed

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,18 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
407407
source_info.span,
408408
)
409409
}
410+
AssertKind::InvalidEnumConstruction(source) => {
411+
let source = codegen_operand(fx, source).load_scalar(fx);
412+
let location = fx.get_caller_location(source_info).load_scalar(fx);
413+
414+
codegen_panic_inner(
415+
fx,
416+
rustc_hir::LangItem::PanicInvalidEnumConstruction,
417+
&[source, location],
418+
*unwind,
419+
source_info.span,
420+
)
421+
}
410422
_ => {
411423
let location = fx.get_caller_location(source_info).load_scalar(fx);
412424

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
777777
// `#[track_caller]` adds an implicit argument.
778778
(LangItem::PanicNullPointerDereference, vec![location])
779779
}
780+
AssertKind::InvalidEnumConstruction(source) => {
781+
let source = self.codegen_operand(bx, source).immediate();
782+
// It's `fn panic_invalid_enum_construction()`,
783+
// `#[track_caller]` adds an implicit argument.
784+
(LangItem::PanicInvalidEnumConstruction, vec![source, location])
785+
}
780786
_ => {
781787
// It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
782788
(msg.panic_function(), vec![location])

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
508508
found: eval_to_int(found)?,
509509
},
510510
NullPointerDereference => NullPointerDereference,
511+
InvalidEnumConstruction(source) => InvalidEnumConstruction(eval_to_int(source)?),
511512
};
512513
Err(ConstEvalErrKind::AssertFailure(err)).into()
513514
}

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ language_item_table! {
310310
PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
311311
PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
312312
PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None;
313+
PanicInvalidEnumConstruction, sym::panic_invalid_enum_construction, panic_invalid_enum_construction, Target::Fn, GenericRequirement::None;
313314
PanicCoroutineResumedDrop, sym::panic_const_coroutine_resumed_drop, panic_const_coroutine_resumed_drop, Target::Fn, GenericRequirement::None;
314315
PanicAsyncFnResumedDrop, sym::panic_const_async_fn_resumed_drop, panic_const_async_fn_resumed_drop, Target::Fn, GenericRequirement::None;
315316
PanicAsyncGenFnResumedDrop, sym::panic_const_async_gen_fn_resumed_drop, panic_const_async_gen_fn_resumed_drop, Target::Fn, GenericRequirement::None;

compiler/rustc_middle/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ middle_assert_gen_resume_after_drop = `gen` fn or block cannot be further iterat
1717
1818
middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further iterated on after it panicked
1919
20+
middle_assert_invalid_enum_construction =
21+
trying to construct an enum from an invalid value `{$source}`
22+
2023
middle_assert_misaligned_ptr_deref =
2124
misaligned pointer dereference: address must be a multiple of {$required} but is {$found}
2225

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ pub enum AssertKind<O> {
10751075
ResumedAfterDrop(CoroutineKind),
10761076
MisalignedPointerDereference { required: O, found: O },
10771077
NullPointerDereference,
1078+
InvalidEnumConstruction(O),
10781079
}
10791080

10801081
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]

compiler/rustc_middle/src/mir/terminator.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ impl<O> AssertKind<O> {
208208
LangItem::PanicGenFnNonePanic
209209
}
210210
NullPointerDereference => LangItem::PanicNullPointerDereference,
211+
InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction,
211212
ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop,
212213
ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
213214
LangItem::PanicAsyncFnResumedDrop
@@ -284,6 +285,9 @@ impl<O> AssertKind<O> {
284285
)
285286
}
286287
NullPointerDereference => write!(f, "\"null pointer dereference occurred\""),
288+
InvalidEnumConstruction(source) => {
289+
write!(f, "\"trying to construct an enum from an invalid value {{}}\", {source:?}")
290+
}
287291
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
288292
write!(f, "\"coroutine resumed after completion\"")
289293
}
@@ -367,6 +371,7 @@ impl<O> AssertKind<O> {
367371
middle_assert_coroutine_resume_after_panic
368372
}
369373
NullPointerDereference => middle_assert_null_ptr_deref,
374+
InvalidEnumConstruction(_) => middle_assert_invalid_enum_construction,
370375
ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
371376
middle_assert_async_resume_after_drop
372377
}
@@ -420,6 +425,9 @@ impl<O> AssertKind<O> {
420425
add!("required", format!("{required:#?}"));
421426
add!("found", format!("{found:#?}"));
422427
}
428+
InvalidEnumConstruction(source) => {
429+
add!("source", format!("{source:#?}"));
430+
}
423431
}
424432
}
425433
}

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ macro_rules! make_mir_visitor {
642642
self.visit_operand(l, location);
643643
self.visit_operand(r, location);
644644
}
645-
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
645+
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) | InvalidEnumConstruction(op) => {
646646
self.visit_operand(op, location);
647647
}
648648
ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ResumedAfterDrop(_) => {

0 commit comments

Comments
 (0)