@@ -54,12 +54,12 @@ use crate::lints::{
5454 BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
5555 BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
5656 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 ,
6363} ;
6464use crate :: nonstandard_style:: { MethodLateContext , method_context} ;
6565use crate :: {
@@ -2986,6 +2986,128 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
29862986 }
29872987}
29882988
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+
29893111declare_lint ! {
29903112 /// The `special_module_name` lint detects module
29913113 /// declarations for files that have a special meaning.
0 commit comments