@@ -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 :: {
@@ -3027,6 +3027,157 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
3027
3027
}
3028
3028
}
3029
3029
3030
+ declare_lint ! {
3031
+ /// The `returning_pointers_to_local_variables` lint detects when pointer
3032
+ /// to stack memory associated with a local variable is returned. That
3033
+ /// pointer is immediately dangling.
3034
+ ///
3035
+ /// ### Example
3036
+ ///
3037
+ /// ```rust,no_run
3038
+ /// fn foo() -> *const i32 {
3039
+ /// let x = 42;
3040
+ /// &x
3041
+ /// }
3042
+ /// ```
3043
+ ///
3044
+ /// {{produces}}
3045
+ ///
3046
+ /// ### Explanation
3047
+ ///
3048
+ /// Returning a pointer to memory refering to a local variable will always
3049
+ /// end up in a dangling pointer after returning.
3050
+ pub RETURNING_POINTERS_TO_LOCAL_VARIABLES ,
3051
+ Warn ,
3052
+ "returning a pointer to stack memory associated with a local variable" ,
3053
+ }
3054
+
3055
+ declare_lint_pass ! ( ReturningPointersToLocalVariables => [ RETURNING_POINTERS_TO_LOCAL_VARIABLES ] ) ;
3056
+
3057
+ impl < ' tcx > LateLintPass < ' tcx > for ReturningPointersToLocalVariables {
3058
+ fn check_fn (
3059
+ & mut self ,
3060
+ cx : & LateContext < ' tcx > ,
3061
+ _: HirFnKind < ' tcx > ,
3062
+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3063
+ body : & ' tcx Body < ' tcx > ,
3064
+ _: Span ,
3065
+ _: LocalDefId ,
3066
+ ) {
3067
+ if !matches ! (
3068
+ fn_decl. output,
3069
+ hir:: FnRetTy :: Return ( & hir:: Ty { kind: hir:: TyKind :: Ptr ( _) , .. } ) ,
3070
+ ) {
3071
+ return ;
3072
+ }
3073
+
3074
+ // Check the block of the function that we're looking at.
3075
+ if let Some ( block) = Self :: get_enclosing_block ( cx, body. value . hir_id ) {
3076
+ match block {
3077
+ hir:: Block {
3078
+ stmts :
3079
+ [
3080
+ ..,
3081
+ hir:: Stmt {
3082
+ kind :
3083
+ hir:: StmtKind :: Semi ( & hir:: Expr {
3084
+ kind : hir:: ExprKind :: Ret ( Some ( return_expr) ) ,
3085
+ ..
3086
+ } ) ,
3087
+ ..
3088
+ } ,
3089
+ ] ,
3090
+ ..
3091
+ } => {
3092
+ Self :: maybe_lint_return_expr ( cx, return_expr, fn_decl. inputs ) ;
3093
+ }
3094
+ hir:: Block { expr : Some ( return_expr) , .. } => {
3095
+ Self :: maybe_lint_return_expr ( cx, return_expr, fn_decl. inputs ) ;
3096
+ }
3097
+ _ => return ,
3098
+ }
3099
+ }
3100
+ }
3101
+ }
3102
+
3103
+ impl ReturningPointersToLocalVariables {
3104
+ /// Evaluates the return expression of a function and emits a lint if it
3105
+ /// returns a pointer to a local variable.
3106
+ fn maybe_lint_return_expr < ' tcx > (
3107
+ cx : & LateContext < ' tcx > ,
3108
+ return_expr : & hir:: Expr < ' tcx > ,
3109
+ params : & ' tcx [ hir:: Ty < ' tcx > ] ,
3110
+ ) {
3111
+ // Early exit if we see that this is a pointer to an input parameter.
3112
+ if Self :: expr_is_param ( cx. typeck_results ( ) , return_expr, params) {
3113
+ return ;
3114
+ }
3115
+
3116
+ match return_expr {
3117
+ hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } => {
3118
+ Self :: maybe_lint_return_expr ( cx, addr_expr, params)
3119
+ }
3120
+ hir:: Expr {
3121
+ kind :
3122
+ hir:: ExprKind :: Cast (
3123
+ hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } ,
3124
+ _,
3125
+ ) ,
3126
+ ..
3127
+ } => Self :: maybe_lint_return_expr ( cx, addr_expr, params) ,
3128
+ hir:: Expr { kind : hir:: ExprKind :: Cast ( expr, _) , .. } => {
3129
+ Self :: maybe_lint_return_expr ( cx, expr, params)
3130
+ }
3131
+ hir:: Expr {
3132
+ kind :
3133
+ hir:: ExprKind :: Path (
3134
+ hir:: QPath :: Resolved ( _, hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ) ,
3135
+ ..,
3136
+ ) ,
3137
+ ..
3138
+ } => cx. emit_span_lint (
3139
+ RETURNING_POINTERS_TO_LOCAL_VARIABLES ,
3140
+ return_expr. span ,
3141
+ BuiltinReturningPointersToLocalVariables ,
3142
+ ) ,
3143
+ _ => ( ) ,
3144
+ }
3145
+ }
3146
+
3147
+ fn expr_is_param < ' tcx > (
3148
+ typeck_results : & ty:: TypeckResults < ' tcx > ,
3149
+ expr : & hir:: Expr < ' tcx > ,
3150
+ params : & ' tcx [ hir:: Ty < ' tcx > ] ,
3151
+ ) -> bool {
3152
+ params
3153
+ . iter ( )
3154
+ . map ( |param| typeck_results. type_dependent_def_id ( param. hir_id ) )
3155
+ . collect :: < Vec < _ > > ( )
3156
+ . contains ( & typeck_results. type_dependent_def_id ( expr. hir_id ) )
3157
+ }
3158
+
3159
+ /// Returns the enclosing block for a [hir::HirId], if available.
3160
+ fn get_enclosing_block < ' tcx > (
3161
+ cx : & LateContext < ' tcx > ,
3162
+ hir_id : hir:: HirId ,
3163
+ ) -> Option < & ' tcx hir:: Block < ' tcx > > {
3164
+ let map = & cx. tcx . hir ( ) ;
3165
+ let enclosing_node =
3166
+ map. get_enclosing_scope ( hir_id) . map ( |enclosing_id| cx. tcx . hir_node ( enclosing_id) ) ;
3167
+ enclosing_node. and_then ( |node| match node {
3168
+ hir:: Node :: Block ( block) => Some ( block) ,
3169
+ hir:: Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Fn { body : eid, .. } , .. } )
3170
+ | hir:: Node :: ImplItem ( & hir:: ImplItem { kind : hir:: ImplItemKind :: Fn ( _, eid) , .. } ) => {
3171
+ match cx. tcx . hir ( ) . body ( eid) . value . kind {
3172
+ hir:: ExprKind :: Block ( block, _) => Some ( block) ,
3173
+ _ => None ,
3174
+ }
3175
+ }
3176
+ _ => None ,
3177
+ } )
3178
+ }
3179
+ }
3180
+
3030
3181
declare_lint ! {
3031
3182
/// The `special_module_name` lint detects module
3032
3183
/// declarations for files that have a special meaning.
0 commit comments