@@ -54,12 +54,12 @@ use crate::lints::{
54
54
BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
55
55
BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
56
56
BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
57
- BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc , BuiltinMutablesTransmutes ,
58
- BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns , BuiltinSpecialModuleNameUsed ,
59
- BuiltinTrivialBounds , BuiltinTypeAliasBounds , BuiltinUngatedAsyncFnTrackCaller ,
60
- BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub ,
61
- BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub ,
62
- BuiltinWhileTrue , InvalidAsmLabel ,
57
+ BuiltinLocalVariablePointerImpl , BuiltinMissingCopyImpl , BuiltinMissingDebugImpl ,
58
+ BuiltinMissingDoc , BuiltinMutablesTransmutes , BuiltinNoMangleGeneric ,
59
+ BuiltinNonShorthandFieldPatterns , BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds ,
60
+ BuiltinTypeAliasBounds , BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit ,
61
+ BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub , BuiltinUnsafe , BuiltinUnstableFeatures ,
62
+ BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub , BuiltinWhileTrue , InvalidAsmLabel ,
63
63
} ;
64
64
use crate :: nonstandard_style:: { MethodLateContext , method_context} ;
65
65
use crate :: {
@@ -2986,6 +2986,128 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
2986
2986
}
2987
2987
}
2988
2988
2989
+ declare_lint ! {
2990
+ /// The `return_local_variable_ptr` lint detects when pointer to stack
2991
+ /// memory associated with a local variable is returned. That pointer
2992
+ /// is immediately dangling.
2993
+ ///
2994
+ /// ### Example
2995
+ ///
2996
+ /// ```rust,no_run
2997
+ /// fn foo() -> *const i32 {
2998
+ /// let x = 42;
2999
+ /// &x
3000
+ /// }
3001
+ /// ```
3002
+ ///
3003
+ /// This will produce:
3004
+ ///
3005
+ /// {{produces}}
3006
+ ///
3007
+ /// ### Explanation
3008
+ ///
3009
+ /// Returning a pointer to memory refering to a local variable will always
3010
+ /// end up in a dangling pointer after returning.
3011
+ pub RETURN_LOCAL_VARIABLE_PTR ,
3012
+ Warn ,
3013
+ "returning a pointer to stack memory associated with a local variable" ,
3014
+ }
3015
+
3016
+ declare_lint_pass ! ( ReturnLocalVariablePointer => [ RETURN_LOCAL_VARIABLE_PTR ] ) ;
3017
+
3018
+ impl < ' tcx > LateLintPass < ' tcx > for ReturnLocalVariablePointer {
3019
+ fn check_fn (
3020
+ & mut self ,
3021
+ cx : & LateContext < ' tcx > ,
3022
+ _: HirFnKind < ' tcx > ,
3023
+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3024
+ body : & ' tcx Body < ' tcx > ,
3025
+ _: Span ,
3026
+ _: LocalDefId ,
3027
+ ) {
3028
+ if !matches ! (
3029
+ fn_decl. output,
3030
+ hir:: FnRetTy :: Return ( & hir:: Ty { kind: hir:: TyKind :: Ptr ( _) , .. } ) ,
3031
+ ) {
3032
+ return ;
3033
+ }
3034
+
3035
+ // Check the block of the function that we're looking at.
3036
+ if let Some ( block) = Self :: get_enclosing_block ( cx, body. value . hir_id ) {
3037
+ match block {
3038
+ hir:: Block {
3039
+ stmts :
3040
+ [
3041
+ ..,
3042
+ hir:: Stmt {
3043
+ kind :
3044
+ hir:: StmtKind :: Semi ( & hir:: Expr {
3045
+ kind : hir:: ExprKind :: Ret ( Some ( return_expr) ) ,
3046
+ ..
3047
+ } ) ,
3048
+ ..
3049
+ } ,
3050
+ ] ,
3051
+ ..
3052
+ } => {
3053
+ Self :: maybe_lint_return_expr ( cx, return_expr) ;
3054
+ }
3055
+ hir:: Block { expr : Some ( return_expr) , .. } => {
3056
+ Self :: maybe_lint_return_expr ( cx, return_expr) ;
3057
+ }
3058
+ _ => return ,
3059
+ }
3060
+ }
3061
+ }
3062
+ }
3063
+
3064
+ impl ReturnLocalVariablePointer {
3065
+ /// Evaluates the return expression of a function and emits a lint if it
3066
+ /// returns a pointer to a local variable.
3067
+ fn maybe_lint_return_expr < ' tcx > ( cx : & LateContext < ' tcx > , return_expr : & hir:: Expr < ' tcx > ) {
3068
+ if let hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. }
3069
+ | hir:: Expr {
3070
+ kind :
3071
+ hir:: ExprKind :: Cast ( hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } , _) ,
3072
+ ..
3073
+ } = return_expr
3074
+ {
3075
+ if let hir:: ExprKind :: Path (
3076
+ hir:: QPath :: Resolved ( _, hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ) ,
3077
+ ..,
3078
+ ) = addr_expr. kind
3079
+ {
3080
+ cx. emit_span_lint (
3081
+ RETURN_LOCAL_VARIABLE_PTR ,
3082
+ return_expr. span ,
3083
+ BuiltinLocalVariablePointerImpl ,
3084
+ ) ;
3085
+ }
3086
+ }
3087
+ }
3088
+
3089
+ /// Returns the enclosing block for a [hir::HirId], if available.
3090
+ fn get_enclosing_block < ' tcx > (
3091
+ cx : & LateContext < ' tcx > ,
3092
+ hir_id : hir:: HirId ,
3093
+ ) -> Option < & ' tcx hir:: Block < ' tcx > > {
3094
+ let map = & cx. tcx . hir ( ) ;
3095
+ let enclosing_node =
3096
+ map. get_enclosing_scope ( hir_id) . map ( |enclosing_id| cx. tcx . hir_node ( enclosing_id) ) ;
3097
+ enclosing_node. and_then ( |node| match node {
3098
+ hir:: Node :: Block ( block) => Some ( block) ,
3099
+ hir:: Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Fn ( _, _, eid) , .. } )
3100
+ | hir:: Node :: ImplItem ( & hir:: ImplItem { kind : hir:: ImplItemKind :: Fn ( _, eid) , .. } ) => {
3101
+ match cx. tcx . hir ( ) . body ( eid) . value . kind {
3102
+ hir:: ExprKind :: Block ( block, _) => Some ( block) ,
3103
+ _ => None ,
3104
+ }
3105
+ }
3106
+ _ => None ,
3107
+ } )
3108
+ }
3109
+ }
3110
+
2989
3111
declare_lint ! {
2990
3112
/// The `special_module_name` lint detects module
2991
3113
/// declarations for files that have a special meaning.
0 commit comments