Skip to content

Commit 4f3342e

Browse files
committed
Insert checks for enum discriminants when debug assertions are enabled
Similar to the existing nullpointer 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) }; ``` This is the only way to create an invalid enum in pure Rust. 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@.
1 parent 6de3a73 commit 4f3342e

File tree

37 files changed

+916
-2
lines changed

37 files changed

+916
-2
lines changed

compiler/rustc_codegen_cranelift/src/base.rs

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

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)