@@ -55,10 +55,10 @@ use crate::lints::{
55
55
BuiltinIncompleteFeatures , BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures ,
56
56
BuiltinKeywordIdents , BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc ,
57
57
BuiltinMutablesTransmutes , BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns ,
58
- BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds , BuiltinTypeAliasBounds ,
59
- BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub ,
60
- BuiltinUnreachablePub , BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment ,
61
- BuiltinUnusedDocCommentSub , BuiltinWhileTrue , InvalidAsmLabel ,
58
+ BuiltinReturningPointersToLocalVariables , BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds ,
59
+ BuiltinTypeAliasBounds , BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit ,
60
+ BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub , BuiltinUnsafe , BuiltinUnstableFeatures ,
61
+ BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub , BuiltinWhileTrue , InvalidAsmLabel ,
62
62
} ;
63
63
use crate :: nonstandard_style:: { MethodLateContext , method_context} ;
64
64
use crate :: {
@@ -3063,6 +3063,159 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
3063
3063
}
3064
3064
}
3065
3065
3066
+ declare_lint ! {
3067
+ /// The `returning_pointers_to_local_variables` lint detects when pointer
3068
+ /// to stack memory associated with a local variable is returned. That
3069
+ /// pointer is immediately dangling.
3070
+ ///
3071
+ /// ### Example
3072
+ ///
3073
+ /// ```rust,no_run
3074
+ /// fn foo() -> *const i32 {
3075
+ /// let x = 42;
3076
+ /// &x
3077
+ /// }
3078
+ /// ```
3079
+ ///
3080
+ /// {{produces}}
3081
+ ///
3082
+ /// ### Explanation
3083
+ ///
3084
+ /// Returning a pointer to memory refering to a local variable will always
3085
+ /// end up in a dangling pointer after returning.
3086
+ pub RETURNING_POINTERS_TO_LOCAL_VARIABLES ,
3087
+ Warn ,
3088
+ "returning a pointer to stack memory associated with a local variable" ,
3089
+ }
3090
+
3091
+ declare_lint_pass ! ( ReturningPointersToLocalVariables => [ RETURNING_POINTERS_TO_LOCAL_VARIABLES ] ) ;
3092
+
3093
+ impl < ' tcx > LateLintPass < ' tcx > for ReturningPointersToLocalVariables {
3094
+ fn check_fn (
3095
+ & mut self ,
3096
+ cx : & LateContext < ' tcx > ,
3097
+ _: HirFnKind < ' tcx > ,
3098
+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3099
+ body : & ' tcx Body < ' tcx > ,
3100
+ _: Span ,
3101
+ _: LocalDefId ,
3102
+ ) {
3103
+ let hir:: FnRetTy :: Return ( & hir:: Ty { kind : hir:: TyKind :: Ptr ( ptr_ty) , .. } ) = fn_decl. output
3104
+ else {
3105
+ return ;
3106
+ } ;
3107
+ if matches ! ( ptr_ty. ty. kind, hir:: TyKind :: Tup ( [ ] ) ) {
3108
+ return ;
3109
+ }
3110
+
3111
+ // Check the block of the function that we're looking at.
3112
+ if let Some ( block) = Self :: get_enclosing_block ( cx, body. value . hir_id ) {
3113
+ match block {
3114
+ & hir:: Block {
3115
+ stmts :
3116
+ & [
3117
+ ..,
3118
+ hir:: Stmt {
3119
+ kind :
3120
+ hir:: StmtKind :: Semi ( & hir:: Expr {
3121
+ kind : hir:: ExprKind :: Ret ( Some ( return_expr) ) ,
3122
+ ..
3123
+ } ) ,
3124
+ ..
3125
+ } ,
3126
+ ] ,
3127
+ ..
3128
+ } => {
3129
+ Self :: maybe_lint_return_expr ( cx, return_expr, fn_decl. inputs ) ;
3130
+ }
3131
+ hir:: Block { expr : Some ( return_expr) , .. } => {
3132
+ Self :: maybe_lint_return_expr ( cx, return_expr, fn_decl. inputs ) ;
3133
+ }
3134
+ _ => return ,
3135
+ }
3136
+ }
3137
+ }
3138
+ }
3139
+
3140
+ impl ReturningPointersToLocalVariables {
3141
+ /// Evaluates the return expression of a function and emits a lint if it
3142
+ /// returns a pointer to a local variable.
3143
+ fn maybe_lint_return_expr < ' tcx > (
3144
+ cx : & LateContext < ' tcx > ,
3145
+ return_expr : & hir:: Expr < ' tcx > ,
3146
+ params : & ' tcx [ hir:: Ty < ' tcx > ] ,
3147
+ ) {
3148
+ // Early exit if we see that this is a pointer to an input parameter.
3149
+ if Self :: expr_is_param ( cx. typeck_results ( ) , return_expr, params) {
3150
+ return ;
3151
+ }
3152
+
3153
+ match return_expr {
3154
+ hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } => {
3155
+ Self :: maybe_lint_return_expr ( cx, addr_expr, params)
3156
+ }
3157
+ hir:: Expr {
3158
+ kind :
3159
+ hir:: ExprKind :: Cast (
3160
+ hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } ,
3161
+ _,
3162
+ ) ,
3163
+ ..
3164
+ } => Self :: maybe_lint_return_expr ( cx, addr_expr, params) ,
3165
+ hir:: Expr { kind : hir:: ExprKind :: Cast ( expr, _) , .. } => {
3166
+ Self :: maybe_lint_return_expr ( cx, expr, params)
3167
+ }
3168
+ hir:: Expr {
3169
+ kind :
3170
+ hir:: ExprKind :: Path (
3171
+ hir:: QPath :: Resolved ( _, hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ) ,
3172
+ ..,
3173
+ ) ,
3174
+ ..
3175
+ } => cx. emit_span_lint (
3176
+ RETURNING_POINTERS_TO_LOCAL_VARIABLES ,
3177
+ return_expr. span ,
3178
+ BuiltinReturningPointersToLocalVariables ,
3179
+ ) ,
3180
+ _ => ( ) ,
3181
+ }
3182
+ }
3183
+
3184
+ fn expr_is_param < ' tcx > (
3185
+ typeck_results : & ty:: TypeckResults < ' tcx > ,
3186
+ expr : & hir:: Expr < ' tcx > ,
3187
+ params : & ' tcx [ hir:: Ty < ' tcx > ] ,
3188
+ ) -> bool {
3189
+ params
3190
+ . iter ( )
3191
+ . map ( |param| typeck_results. type_dependent_def_id ( param. hir_id ) )
3192
+ . collect :: < Vec < _ > > ( )
3193
+ . contains ( & typeck_results. type_dependent_def_id ( expr. hir_id ) )
3194
+ }
3195
+
3196
+ /// Returns the enclosing block for a [hir::HirId], if available.
3197
+ fn get_enclosing_block < ' tcx > (
3198
+ cx : & LateContext < ' tcx > ,
3199
+ hir_id : hir:: HirId ,
3200
+ ) -> Option < & ' tcx hir:: Block < ' tcx > > {
3201
+ let enclosing_node = cx
3202
+ . tcx
3203
+ . hir_get_enclosing_scope ( hir_id)
3204
+ . map ( |enclosing_id| cx. tcx . hir_node ( enclosing_id) ) ;
3205
+ enclosing_node. and_then ( |node| match node {
3206
+ hir:: Node :: Block ( block) => Some ( block) ,
3207
+ hir:: Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Fn { body : eid, .. } , .. } )
3208
+ | hir:: Node :: ImplItem ( & hir:: ImplItem { kind : hir:: ImplItemKind :: Fn ( _, eid) , .. } ) => {
3209
+ match cx. tcx . hir_body ( eid) . value . kind {
3210
+ hir:: ExprKind :: Block ( block, _) => Some ( block) ,
3211
+ _ => None ,
3212
+ }
3213
+ }
3214
+ _ => None ,
3215
+ } )
3216
+ }
3217
+ }
3218
+
3066
3219
declare_lint ! {
3067
3220
/// The `special_module_name` lint detects module
3068
3221
/// declarations for files that have a special meaning.
0 commit comments