@@ -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 :: {
@@ -3063,6 +3063,159 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
30633063 }
30643064}
30653065
3066+ declare_lint ! {
3067+ /// The `returning_pointers_to_local_variables` lint detects when pointer
3068+ /// to stack memory associated with a local variable is returned. That
3069+ /// pointer is immediately dangling.
3070+ ///
3071+ /// ### Example
3072+ ///
3073+ /// ```rust,no_run
3074+ /// fn foo() -> *const i32 {
3075+ /// let x = 42;
3076+ /// &x
3077+ /// }
3078+ /// ```
3079+ ///
3080+ /// {{produces}}
3081+ ///
3082+ /// ### Explanation
3083+ ///
3084+ /// Returning a pointer to memory refering to a local variable will always
3085+ /// end up in a dangling pointer after returning.
3086+ pub RETURNING_POINTERS_TO_LOCAL_VARIABLES ,
3087+ Warn ,
3088+ "returning a pointer to stack memory associated with a local variable" ,
3089+ }
3090+
3091+ declare_lint_pass ! ( ReturningPointersToLocalVariables => [ RETURNING_POINTERS_TO_LOCAL_VARIABLES ] ) ;
3092+
3093+ impl < ' tcx > LateLintPass < ' tcx > for ReturningPointersToLocalVariables {
3094+ fn check_fn (
3095+ & mut self ,
3096+ cx : & LateContext < ' tcx > ,
3097+ _: HirFnKind < ' tcx > ,
3098+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3099+ body : & ' tcx Body < ' tcx > ,
3100+ _: Span ,
3101+ _: LocalDefId ,
3102+ ) {
3103+ let hir:: FnRetTy :: Return ( & hir:: Ty { kind : hir:: TyKind :: Ptr ( ptr_ty) , .. } ) = fn_decl. output
3104+ else {
3105+ return ;
3106+ } ;
3107+ if matches ! ( ptr_ty. ty. kind, hir:: TyKind :: Tup ( [ ] ) ) {
3108+ return ;
3109+ }
3110+
3111+ // Check the block of the function that we're looking at.
3112+ if let Some ( block) = Self :: get_enclosing_block ( cx, body. value . hir_id ) {
3113+ match block {
3114+ & hir:: Block {
3115+ stmts :
3116+ & [
3117+ ..,
3118+ hir:: Stmt {
3119+ kind :
3120+ hir:: StmtKind :: Semi ( & hir:: Expr {
3121+ kind : hir:: ExprKind :: Ret ( Some ( return_expr) ) ,
3122+ ..
3123+ } ) ,
3124+ ..
3125+ } ,
3126+ ] ,
3127+ ..
3128+ } => {
3129+ Self :: maybe_lint_return_expr ( cx, return_expr, fn_decl. inputs ) ;
3130+ }
3131+ hir:: Block { expr : Some ( return_expr) , .. } => {
3132+ Self :: maybe_lint_return_expr ( cx, return_expr, fn_decl. inputs ) ;
3133+ }
3134+ _ => return ,
3135+ }
3136+ }
3137+ }
3138+ }
3139+
3140+ impl ReturningPointersToLocalVariables {
3141+ /// Evaluates the return expression of a function and emits a lint if it
3142+ /// returns a pointer to a local variable.
3143+ fn maybe_lint_return_expr < ' tcx > (
3144+ cx : & LateContext < ' tcx > ,
3145+ return_expr : & hir:: Expr < ' tcx > ,
3146+ params : & ' tcx [ hir:: Ty < ' tcx > ] ,
3147+ ) {
3148+ // Early exit if we see that this is a pointer to an input parameter.
3149+ if Self :: expr_is_param ( cx. typeck_results ( ) , return_expr, params) {
3150+ return ;
3151+ }
3152+
3153+ match return_expr {
3154+ hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } => {
3155+ Self :: maybe_lint_return_expr ( cx, addr_expr, params)
3156+ }
3157+ hir:: Expr {
3158+ kind :
3159+ hir:: ExprKind :: Cast (
3160+ hir:: Expr { kind : hir:: ExprKind :: AddrOf ( _, _, addr_expr) , .. } ,
3161+ _,
3162+ ) ,
3163+ ..
3164+ } => Self :: maybe_lint_return_expr ( cx, addr_expr, params) ,
3165+ hir:: Expr { kind : hir:: ExprKind :: Cast ( expr, _) , .. } => {
3166+ Self :: maybe_lint_return_expr ( cx, expr, params)
3167+ }
3168+ hir:: Expr {
3169+ kind :
3170+ hir:: ExprKind :: Path (
3171+ hir:: QPath :: Resolved ( _, hir:: Path { res : hir:: def:: Res :: Local ( _) , .. } ) ,
3172+ ..,
3173+ ) ,
3174+ ..
3175+ } => cx. emit_span_lint (
3176+ RETURNING_POINTERS_TO_LOCAL_VARIABLES ,
3177+ return_expr. span ,
3178+ BuiltinReturningPointersToLocalVariables ,
3179+ ) ,
3180+ _ => ( ) ,
3181+ }
3182+ }
3183+
3184+ fn expr_is_param < ' tcx > (
3185+ typeck_results : & ty:: TypeckResults < ' tcx > ,
3186+ expr : & hir:: Expr < ' tcx > ,
3187+ params : & ' tcx [ hir:: Ty < ' tcx > ] ,
3188+ ) -> bool {
3189+ params
3190+ . iter ( )
3191+ . map ( |param| typeck_results. type_dependent_def_id ( param. hir_id ) )
3192+ . collect :: < Vec < _ > > ( )
3193+ . contains ( & typeck_results. type_dependent_def_id ( expr. hir_id ) )
3194+ }
3195+
3196+ /// Returns the enclosing block for a [hir::HirId], if available.
3197+ fn get_enclosing_block < ' tcx > (
3198+ cx : & LateContext < ' tcx > ,
3199+ hir_id : hir:: HirId ,
3200+ ) -> Option < & ' tcx hir:: Block < ' tcx > > {
3201+ let enclosing_node = cx
3202+ . tcx
3203+ . hir_get_enclosing_scope ( hir_id)
3204+ . map ( |enclosing_id| cx. tcx . hir_node ( enclosing_id) ) ;
3205+ enclosing_node. and_then ( |node| match node {
3206+ hir:: Node :: Block ( block) => Some ( block) ,
3207+ hir:: Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Fn { body : eid, .. } , .. } )
3208+ | hir:: Node :: ImplItem ( & hir:: ImplItem { kind : hir:: ImplItemKind :: Fn ( _, eid) , .. } ) => {
3209+ match cx. tcx . hir_body ( eid) . value . kind {
3210+ hir:: ExprKind :: Block ( block, _) => Some ( block) ,
3211+ _ => None ,
3212+ }
3213+ }
3214+ _ => None ,
3215+ } )
3216+ }
3217+ }
3218+
30663219declare_lint ! {
30673220 /// The `special_module_name` lint detects module
30683221 /// declarations for files that have a special meaning.
0 commit comments