@@ -64,16 +64,23 @@ AST_MATCHER(CXXRecordDecl, correctHandleCaptureThisLambda) {
6464
6565constexpr const char *DefaultFunctionWrapperTypes =
6666 " ::std::function;::std::move_only_function;::boost::function" ;
67+ constexpr const char *DefaultBindFunctions =
68+ " ::std::bind;::boost::bind;::std::bind_front;::std::bind_back;"
69+ " ::boost::compat::bind_front;::boost::compat::bind_back" ;
6770
6871CapturingThisInMemberVariableCheck::CapturingThisInMemberVariableCheck (
6972 StringRef Name, ClangTidyContext *Context)
7073 : ClangTidyCheck(Name, Context),
7174 FunctionWrapperTypes (utils::options::parseStringList(
72- Options.get(" FunctionWrapperTypes" , DefaultFunctionWrapperTypes))) {}
75+ Options.get(" FunctionWrapperTypes" , DefaultFunctionWrapperTypes))),
76+ BindFunctions(utils::options::parseStringList(
77+ Options.get(" BindFunctions" , DefaultBindFunctions))) {}
7378void CapturingThisInMemberVariableCheck::storeOptions (
7479 ClangTidyOptions::OptionMap &Opts) {
7580 Options.store (Opts, " FunctionWrapperTypes" ,
7681 utils::options::serializeStringList (FunctionWrapperTypes));
82+ Options.store (Opts, " BindFunctions" ,
83+ utils::options::serializeStringList (BindFunctions));
7784}
7885
7986void CapturingThisInMemberVariableCheck::registerMatchers (MatchFinder *Finder) {
@@ -87,33 +94,52 @@ void CapturingThisInMemberVariableCheck::registerMatchers(MatchFinder *Finder) {
8794 // [self = this]
8895 capturesVar (varDecl (hasInitializer (cxxThisExpr ())))));
8996 auto IsLambdaCapturingThis =
90- lambdaExpr (hasAnyCapture (CaptureThis.bind (" capture" ))).bind (" lambda" );
91- auto IsInitWithLambda =
92- anyOf (IsLambdaCapturingThis,
93- cxxConstructExpr (hasArgument (0 , IsLambdaCapturingThis)));
97+ lambdaExpr (hasAnyCapture (CaptureThis)).bind (" lambda" );
98+
99+ auto IsBindCapturingThis =
100+ callExpr (
101+ callee (functionDecl (matchers::matchesAnyListedName (BindFunctions))
102+ .bind (" callee" )),
103+ hasAnyArgument (cxxThisExpr ()))
104+ .bind (" bind" );
105+
106+ auto IsInitWithLambdaOrBind =
107+ anyOf (IsLambdaCapturingThis, IsBindCapturingThis,
108+ cxxConstructExpr (hasArgument (
109+ 0 , anyOf (IsLambdaCapturingThis, IsBindCapturingThis))));
110+
94111 Finder->addMatcher (
95112 cxxRecordDecl (
96113 anyOf (has (cxxConstructorDecl (
97114 unless (isCopyConstructor ()), unless (isMoveConstructor ()),
98115 hasAnyConstructorInitializer (cxxCtorInitializer (
99116 isMemberInitializer (), forField (IsStdFunctionField),
100- withInitializer (IsInitWithLambda ))))),
117+ withInitializer (IsInitWithLambdaOrBind ))))),
101118 has (fieldDecl (IsStdFunctionField,
102- hasInClassInitializer (IsInitWithLambda )))),
119+ hasInClassInitializer (IsInitWithLambdaOrBind )))),
103120 unless (correctHandleCaptureThisLambda ())),
104121 this );
105122}
106-
107123void CapturingThisInMemberVariableCheck::check (
108124 const MatchFinder::MatchResult &Result) {
109- const auto *Capture = Result.Nodes .getNodeAs <LambdaCapture>(" capture" );
110- const auto *Lambda = Result.Nodes .getNodeAs <LambdaExpr>(" lambda" );
125+ if (const auto *Lambda = Result.Nodes .getNodeAs <LambdaExpr>(" lambda" )) {
126+ diag (Lambda->getBeginLoc (),
127+ " 'this' captured by a lambda and stored in a class member variable; "
128+ " disable implicit class copying/moving to prevent potential "
129+ " use-after-free" );
130+ } else if (const auto *Bind = Result.Nodes .getNodeAs <CallExpr>(" bind" )) {
131+ const auto *Callee = Result.Nodes .getNodeAs <FunctionDecl>(" callee" );
132+ assert (Callee);
133+ diag (Bind->getBeginLoc (),
134+ " 'this' captured by a '%0' call and stored in a class member "
135+ " variable; disable implicit class copying/moving to prevent potential "
136+ " use-after-free" )
137+ << Callee->getQualifiedNameAsString ();
138+ }
139+
111140 const auto *Field = Result.Nodes .getNodeAs <FieldDecl>(" field" );
112- diag (Lambda->getBeginLoc (),
113- " 'this' captured by a lambda and stored in a class member variable; "
114- " disable implicit class copying/moving to prevent potential "
115- " use-after-free" )
116- << Capture->getLocation ();
141+ assert (Field);
142+
117143 diag (Field->getLocation (),
118144 " class member of type '%0' that stores captured 'this'" ,
119145 DiagnosticIDs::Note)
0 commit comments