@@ -55,10 +55,10 @@ use crate::lints::{
5555 BuiltinIncompleteFeatures , BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures ,
5656 BuiltinKeywordIdents , BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc ,
5757 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 ,
6262} ;
6363use crate :: nonstandard_style:: { MethodLateContext , method_context} ;
6464use crate :: {
@@ -3027,6 +3027,157 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
30273027 }
30283028}
30293029
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+
30303181declare_lint ! {
30313182 /// The `special_module_name` lint detects module
30323183 /// declarations for files that have a special meaning.
0 commit comments