11use rustc_abi:: ExternAbi ;
22use rustc_hir:: { self as hir, Expr , ExprKind } ;
3- use rustc_middle:: ty:: layout:: { LayoutCx , TyAndLayout } ;
4- use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
3+ use rustc_middle:: ty:: layout:: TyAndLayout ;
4+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt } ;
55use rustc_session:: { declare_lint, declare_lint_pass} ;
66
77use crate :: { LateContext , LateLintPass , LintContext , lints} ;
@@ -86,11 +86,12 @@ fn check_cmse_call_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
8686 continue ;
8787 } ;
8888
89- if layout_contains_union ( cx. tcx , & layout) {
89+ if !is_transmutable_to_array_u8 ( cx. tcx , ty. clone ( ) , layout) {
90+ // Some part of the source type may be uninitialized.
9091 cx. emit_span_lint (
9192 CMSE_UNINITIALIZED_LEAK ,
9293 arg. span ,
93- lints:: CmseUnionMayLeakInformation ,
94+ lints:: CmseUninitializedMayLeakInformation ,
9495 ) ;
9596 }
9697 }
@@ -126,11 +127,12 @@ fn check_cmse_entry_return<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
126127 }
127128
128129 let typing_env = ty:: TypingEnv :: fully_monomorphized ( ) ;
130+
129131 let Ok ( ret_layout) = cx. tcx . layout_of ( typing_env. as_query_input ( return_type) ) else {
130132 return ;
131133 } ;
132134
133- if layout_contains_union ( cx. tcx , & ret_layout) {
135+ if ! is_transmutable_to_array_u8 ( cx. tcx , return_type . clone ( ) , ret_layout) {
134136 let return_expr_span = if is_implicit_return {
135137 match expr. kind {
136138 ExprKind :: Block ( block, _) => match block. expr {
@@ -143,46 +145,39 @@ fn check_cmse_entry_return<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
143145 expr. span
144146 } ;
145147
148+ // Some part of the source type may be uninitialized.
146149 cx. emit_span_lint (
147150 CMSE_UNINITIALIZED_LEAK ,
148151 return_expr_span,
149- lints:: CmseUnionMayLeakInformation ,
152+ lints:: CmseUninitializedMayLeakInformation ,
150153 ) ;
151154 }
152155}
153156
154- /// Check whether any part of the layout is a union, which may contain secure data still.
155- fn layout_contains_union < ' tcx > ( tcx : TyCtxt < ' tcx > , layout : & TyAndLayout < ' tcx > ) -> bool {
156- if layout. ty . is_union ( ) {
157- return true ;
158- }
159-
160- let typing_env = ty:: TypingEnv :: fully_monomorphized ( ) ;
161- let cx = LayoutCx :: new ( tcx, typing_env) ;
162-
163- match & layout. variants {
164- rustc_abi:: Variants :: Single { .. } => {
165- for i in 0 ..layout. fields . count ( ) {
166- if layout_contains_union ( tcx, & layout. field ( & cx, i) ) {
167- return true ;
168- }
169- }
170- }
171-
172- rustc_abi:: Variants :: Multiple { variants, .. } => {
173- for ( variant_idx, _vdata) in variants. iter_enumerated ( ) {
174- let variant_layout = layout. for_variant ( & cx, variant_idx) ;
175-
176- for i in 0 ..variant_layout. fields . count ( ) {
177- if layout_contains_union ( tcx, & variant_layout. field ( & cx, i) ) {
178- return true ;
179- }
180- }
181- }
182- }
183-
184- rustc_abi:: Variants :: Empty => { }
157+ /// Check whether the source type `T` can be safely transmuted to `[u8; size_of::<T>()]`.
158+ ///
159+ /// If the transmute is valid, `T` must be fully initialized. Otherwise, parts of it may be
160+ /// uninitialized, which should trigger the lint defined by this module.
161+ fn is_transmutable_to_array_u8 < ' tcx > (
162+ tcx : TyCtxt < ' tcx > ,
163+ ty : Ty < ' tcx > ,
164+ layout : TyAndLayout < ' tcx > ,
165+ ) -> bool {
166+ use rustc_transmute:: { Answer , Assume , TransmuteTypeEnv , Types } ;
167+
168+ let mut transmute_env = TransmuteTypeEnv :: new ( tcx) ;
169+ let assume = Assume { alignment : true , lifetimes : true , safety : false , validity : false } ;
170+
171+ let array_u8_ty = Ty :: new_array_with_const_len (
172+ tcx,
173+ tcx. types . u8 ,
174+ ty:: Const :: from_target_usize ( tcx, layout. size . bytes ( ) ) ,
175+ ) ;
176+
177+ let types = Types { src : ty, dst : array_u8_ty } ;
178+
179+ match transmute_env. is_transmutable ( types, assume) {
180+ Answer :: Yes => true ,
181+ Answer :: No ( _) | Answer :: If ( _) => false ,
185182 }
186-
187- false
188183}
0 commit comments