@@ -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,134 @@ 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
+ /// ```text
3006
+ /// error: returning a pointer to stack memory associated with a local variable
3007
+ /// --> <source>:12:5
3008
+ /// |
3009
+ /// LL| &x
3010
+ /// | ^^
3011
+ /// ```
3012
+ ///
3013
+ /// ### Explanation
3014
+ ///
3015
+ /// Returning a pointer to memory refering to a local variable will always
3016
+ /// end up in a dangling pointer after returning.
3017
+ pub RETURN_LOCAL_VARIABLE_PTR ,
3018
+ Warn ,
3019
+ "returning a pointer to stack memory associated with a local variable" ,
3020
+ }
3021
+
3022
+ declare_lint_pass ! ( ReturnLocalVariablePointer => [ RETURN_LOCAL_VARIABLE_PTR ] ) ;
3023
+
3024
+ impl < ' tcx > LateLintPass < ' tcx > for ReturnLocalVariablePointer {
3025
+ fn check_fn (
3026
+ & mut self ,
3027
+ cx : & LateContext < ' tcx > ,
3028
+ _: HirFnKind < ' tcx > ,
3029
+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3030
+ body : & ' tcx Body < ' tcx > ,
3031
+ _: Span ,
3032
+ _: LocalDefId ,
3033
+ ) {
3034
+ if !matches ! (
3035
+ fn_decl. output,
3036
+ hir:: FnRetTy :: Return ( & hir:: Ty { kind: hir:: TyKind :: Ptr ( _) , .. } ) ,
3037
+ ) {
3038
+ return ;
3039
+ }
3040
+
3041
+ // Check the block of the function that we're looking at.
3042
+ if let Some ( block) = Self :: get_enclosing_block ( cx, body. value . hir_id ) {
3043
+ match block {
3044
+ hir:: Block {
3045
+ stmts :
3046
+ [
3047
+ ..,
3048
+ hir:: Stmt {
3049
+ kind :
3050
+ hir:: StmtKind :: Semi ( & hir:: Expr {
3051
+ kind : hir:: ExprKind :: Ret ( Some ( return_expr) ) ,
3052
+ ..
3053
+ } ) ,
3054
+ ..
3055
+ } ,
3056
+ ] ,
3057
+ ..
3058
+ } => {
3059
+ Self :: maybe_lint_return_expr ( cx, return_expr) ;
3060
+ }
3061
+ hir:: Block { expr : Some ( return_expr) , .. } => {
3062
+ Self :: maybe_lint_return_expr ( cx, return_expr) ;
3063
+ }
3064
+ _ => return ,
3065
+ }
3066
+ }
3067
+ }
3068
+ }
3069
+
3070
+ impl ReturnLocalVariablePointer {
3071
+ /// Evaluates the return expression of a function and emits a lint if it
3072
+ /// returns a pointer to a local variable.
3073
+ fn maybe_lint_return_expr < ' tcx > ( cx : & LateContext < ' tcx > , return_expr : & hir:: Expr < ' tcx > ) {
3074
+ if let hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. }
3075
+ | hir:: Expr {
3076
+ kind :
3077
+ hir:: ExprKind :: Cast ( hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } , _) ,
3078
+ ..
3079
+ } = return_expr
3080
+ {
3081
+ if let hir:: ExprKind :: Path (
3082
+ hir:: QPath :: Resolved ( _, hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ) ,
3083
+ ..,
3084
+ ) = addr_expr. kind
3085
+ {
3086
+ cx. emit_span_lint (
3087
+ RETURN_LOCAL_VARIABLE_PTR ,
3088
+ return_expr. span ,
3089
+ BuiltinLocalVariablePointerImpl ,
3090
+ ) ;
3091
+ }
3092
+ }
3093
+ }
3094
+
3095
+ /// Returns the enclosing block for a [hir::HirId], if available.
3096
+ fn get_enclosing_block < ' tcx > (
3097
+ cx : & LateContext < ' tcx > ,
3098
+ hir_id : hir:: HirId ,
3099
+ ) -> Option < & ' tcx hir:: Block < ' tcx > > {
3100
+ let map = & cx. tcx . hir ( ) ;
3101
+ let enclosing_node =
3102
+ map. get_enclosing_scope ( hir_id) . map ( |enclosing_id| cx. tcx . hir_node ( enclosing_id) ) ;
3103
+ enclosing_node. and_then ( |node| match node {
3104
+ hir:: Node :: Block ( block) => Some ( block) ,
3105
+ hir:: Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Fn ( _, _, eid) , .. } )
3106
+ | hir:: Node :: ImplItem ( & hir:: ImplItem { kind : hir:: ImplItemKind :: Fn ( _, eid) , .. } ) => {
3107
+ match cx. tcx . hir ( ) . body ( eid) . value . kind {
3108
+ hir:: ExprKind :: Block ( block, _) => Some ( block) ,
3109
+ _ => None ,
3110
+ }
3111
+ }
3112
+ _ => None ,
3113
+ } )
3114
+ }
3115
+ }
3116
+
2989
3117
declare_lint ! {
2990
3118
/// The `special_module_name` lint detects module
2991
3119
/// declarations for files that have a special meaning.
0 commit comments