@@ -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,134 @@ 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+ /// ```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+
29893117declare_lint ! {
29903118 /// The `special_module_name` lint detects module
29913119 /// declarations for files that have a special meaning.
0 commit comments