1
1
use rustc_index:: IndexVec ;
2
- use rustc_middle:: mir:: interpret :: Scalar ;
2
+ use rustc_middle:: mir:: visit :: { MutatingUseContext , NonMutatingUseContext , PlaceContext } ;
3
3
use rustc_middle:: mir:: * ;
4
4
use rustc_middle:: ty:: { Ty , TyCtxt } ;
5
5
use rustc_session:: Session ;
@@ -26,6 +26,7 @@ fn insert_null_check<'tcx>(
26
26
tcx : TyCtxt < ' tcx > ,
27
27
pointer : Place < ' tcx > ,
28
28
pointee_ty : Ty < ' tcx > ,
29
+ context : PlaceContext ,
29
30
local_decls : & mut IndexVec < Local , LocalDecl < ' tcx > > ,
30
31
stmts : & mut Vec < Statement < ' tcx > > ,
31
32
source_info : SourceInfo ,
@@ -42,30 +43,51 @@ fn insert_null_check<'tcx>(
42
43
let addr = local_decls. push ( LocalDecl :: with_source_info ( tcx. types . usize , source_info) ) . into ( ) ;
43
44
stmts. push ( Statement { source_info, kind : StatementKind :: Assign ( Box :: new ( ( addr, rvalue) ) ) } ) ;
44
45
45
- // Get size of the pointee (zero-sized reads and writes are allowed).
46
- let rvalue = Rvalue :: NullaryOp ( NullOp :: SizeOf , pointee_ty) ;
47
- let sizeof_pointee =
48
- local_decls. push ( LocalDecl :: with_source_info ( tcx. types . usize , source_info) ) . into ( ) ;
49
- stmts. push ( Statement {
50
- source_info,
51
- kind : StatementKind :: Assign ( Box :: new ( ( sizeof_pointee, rvalue) ) ) ,
52
- } ) ;
53
-
54
- // Check that the pointee is not a ZST.
55
46
let zero = Operand :: Constant ( Box :: new ( ConstOperand {
56
47
span : source_info. span ,
57
48
user_ty : None ,
58
- const_ : Const :: Val ( ConstValue :: Scalar ( Scalar :: from_target_usize ( 0 , & tcx) ) , tcx. types . usize ) ,
49
+ const_ : Const :: Val ( ConstValue :: from_target_usize ( 0 , & tcx) , tcx. types . usize ) ,
59
50
} ) ) ;
60
- let is_pointee_no_zst =
61
- local_decls. push ( LocalDecl :: with_source_info ( tcx. types . bool , source_info) ) . into ( ) ;
62
- stmts. push ( Statement {
63
- source_info,
64
- kind : StatementKind :: Assign ( Box :: new ( (
65
- is_pointee_no_zst,
66
- Rvalue :: BinaryOp ( BinOp :: Ne , Box :: new ( ( Operand :: Copy ( sizeof_pointee) , zero. clone ( ) ) ) ) ,
67
- ) ) ) ,
68
- } ) ;
51
+
52
+ let pointee_should_be_checked = match context {
53
+ // Borrows pointing to "null" are UB even if the pointee is a ZST.
54
+ PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow )
55
+ | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow ) => {
56
+ // Pointer should be checked unconditionally.
57
+ Operand :: Constant ( Box :: new ( ConstOperand {
58
+ span : source_info. span ,
59
+ user_ty : None ,
60
+ const_ : Const :: Val ( ConstValue :: from_bool ( true ) , tcx. types . bool ) ,
61
+ } ) )
62
+ }
63
+ // Other usages of null pointers only are UB if the pointee is not a ZST.
64
+ _ => {
65
+ let rvalue = Rvalue :: NullaryOp ( NullOp :: SizeOf , pointee_ty) ;
66
+ let sizeof_pointee =
67
+ local_decls. push ( LocalDecl :: with_source_info ( tcx. types . usize , source_info) ) . into ( ) ;
68
+ stmts. push ( Statement {
69
+ source_info,
70
+ kind : StatementKind :: Assign ( Box :: new ( ( sizeof_pointee, rvalue) ) ) ,
71
+ } ) ;
72
+
73
+ // Check that the pointee is not a ZST.
74
+ let is_pointee_not_zst =
75
+ local_decls. push ( LocalDecl :: with_source_info ( tcx. types . bool , source_info) ) . into ( ) ;
76
+ stmts. push ( Statement {
77
+ source_info,
78
+ kind : StatementKind :: Assign ( Box :: new ( (
79
+ is_pointee_not_zst,
80
+ Rvalue :: BinaryOp (
81
+ BinOp :: Ne ,
82
+ Box :: new ( ( Operand :: Copy ( sizeof_pointee) , zero. clone ( ) ) ) ,
83
+ ) ,
84
+ ) ) ) ,
85
+ } ) ;
86
+
87
+ // Pointer needs to be checked only if pointee is not a ZST.
88
+ Operand :: Copy ( is_pointee_not_zst)
89
+ }
90
+ } ;
69
91
70
92
// Check whether the pointer is null.
71
93
let is_null = local_decls. push ( LocalDecl :: with_source_info ( tcx. types . bool , source_info) ) . into ( ) ;
@@ -77,7 +99,8 @@ fn insert_null_check<'tcx>(
77
99
) ) ) ,
78
100
} ) ;
79
101
80
- // We want to throw an exception if the pointer is null and doesn't point to a ZST.
102
+ // We want to throw an exception if the pointer is null and the pointee is not unconditionally
103
+ // allowed (which for all non-borrow place uses, is when the pointee is ZST).
81
104
let should_throw_exception =
82
105
local_decls. push ( LocalDecl :: with_source_info ( tcx. types . bool , source_info) ) . into ( ) ;
83
106
stmts. push ( Statement {
@@ -86,7 +109,7 @@ fn insert_null_check<'tcx>(
86
109
should_throw_exception,
87
110
Rvalue :: BinaryOp (
88
111
BinOp :: BitAnd ,
89
- Box :: new ( ( Operand :: Copy ( is_null) , Operand :: Copy ( is_pointee_no_zst ) ) ) ,
112
+ Box :: new ( ( Operand :: Copy ( is_null) , pointee_should_be_checked ) ) ,
90
113
) ,
91
114
) ) ) ,
92
115
} ) ;
0 commit comments