Skip to content

Commit 546567e

Browse files
committed
clang-tidy: add bugprone-taxi-async-use-after-free
1 parent d597452 commit 546567e

File tree

8 files changed

+137
-0
lines changed

8 files changed

+137
-0
lines changed

clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
#include "SwappedArgumentsCheck.h"
8484
#include "SwitchMissingDefaultCaseCheck.h"
8585
#include "TaggedUnionMemberCountCheck.h"
86+
#include "TaxiAsyncUseAfterFreeCheck.h"
8687
#include "TerminatingContinueCheck.h"
8788
#include "ThrowKeywordMissingCheck.h"
8889
#include "TooSmallLoopVariableCheck.h"
@@ -151,6 +152,8 @@ class BugproneModule : public ClangTidyModule {
151152
"bugprone-incorrect-enable-if");
152153
CheckFactories.registerCheck<IncorrectEnableSharedFromThisCheck>(
153154
"bugprone-incorrect-enable-shared-from-this");
155+
CheckFactories.registerCheck<TaxiAsyncUseAfterFreeCheck>(
156+
"bugprone-taxi-async-use-after-free");
154157
CheckFactories.registerCheck<UnintendedCharOstreamOutputCheck>(
155158
"bugprone-unintended-char-ostream-output");
156159
CheckFactories.registerCheck<ReturnConstRefFromParameterCheck>(

clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC
3030
InaccurateEraseCheck.cpp
3131
IncorrectEnableIfCheck.cpp
3232
IncorrectEnableSharedFromThisCheck.cpp
33+
TaxiAsyncUseAfterFreeCheck.cpp
3334
UnintendedCharOstreamOutputCheck.cpp
3435
ReturnConstRefFromParameterCheck.cpp
3536
SuspiciousStringviewDataUsageCheck.cpp
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- TaxiAsyncUseAfterFreeCheck.cpp - clang-tidy ----------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "TaxiAsyncUseAfterFreeCheck.h"
10+
#include "clang/ASTMatchers/ASTMatchFinder.h"
11+
12+
using namespace clang::ast_matchers;
13+
14+
namespace clang::tidy::bugprone {
15+
16+
void TaxiAsyncUseAfterFreeCheck::registerMatchers(MatchFinder* Finder) {
17+
auto hasAsyncName = hasAnyName(
18+
"Async", "AsyncNoSpan", "SharedAsyncNoSpan", "CriticalAsyncNoSpan",
19+
"SharedCriticalAsyncNoSpan", "CriticalAsync", "SharedCriticalAsync");
20+
21+
Finder->addMatcher(
22+
lambdaExpr(
23+
hasParent(materializeTemporaryExpr(hasParent(callExpr(
24+
hasParent(cxxMemberCallExpr(
25+
26+
callee(cxxMethodDecl(hasName("push_back"))),
27+
28+
on(declRefExpr(hasDeclaration(varDecl().bind("tasks")))))),
29+
30+
callee(functionDecl(hasAsyncName)))))))
31+
.bind("lambda"),
32+
this);
33+
}
34+
35+
void TaxiAsyncUseAfterFreeCheck::check(const MatchFinder::MatchResult& Result) {
36+
const auto* MatchedLambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
37+
const auto* MatchedTasks = Result.Nodes.getNodeAs<VarDecl>("tasks");
38+
const SourceLocation TasksLocation = MatchedTasks->getLocation();
39+
40+
for (const auto& Capture : MatchedLambda->captures()) {
41+
if (!Capture.capturesVariable() || Capture.getCaptureKind() != LCK_ByRef)
42+
continue;
43+
44+
const ValueDecl* CapturedVarDecl = Capture.getCapturedVar();
45+
if (CapturedVarDecl->getLocation() >= TasksLocation) {
46+
diag(Capture.getLocation(), "captured here");
47+
diag(CapturedVarDecl->getLocation(), "variable can be used after free");
48+
diag(TasksLocation, "std::vector<Task> can die after variable");
49+
}
50+
}
51+
}
52+
53+
} // namespace clang::tidy::bugprone
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===--- TaxiAsyncUseAfterFreeCheck.h - clang-tidy --------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAXIASYNCUSEAFTERFREECHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAXIASYNCUSEAFTERFREECHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::bugprone {
15+
16+
/// Use-after-free for engine::Async.
17+
///
18+
/// For the user-facing documentation see:
19+
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/taxi-async-use-after-free.html
20+
class TaxiAsyncUseAfterFreeCheck : public ClangTidyCheck {
21+
public:
22+
TaxiAsyncUseAfterFreeCheck(StringRef Name, ClangTidyContext *Context)
23+
: ClangTidyCheck(Name, Context) {}
24+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
25+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
26+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
27+
return LangOpts.CPlusPlus;
28+
}
29+
};
30+
31+
} // namespace clang::tidy::bugprone
32+
33+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAXIASYNCUSEAFTERFREECHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ New checks
124124
pointer and store it as class members without handle the copy and move
125125
constructors and the assignments.
126126

127+
- New :doc:`bugprone-taxi-async-use-after-free
128+
<clang-tidy/checks/bugprone/taxi-async-use-after-free>` check.
129+
130+
Use-after-free for engine::Async.
131+
127132
- New :doc:`bugprone-unintended-char-ostream-output
128133
<clang-tidy/checks/bugprone/unintended-char-ostream-output>` check.
129134

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. title:: clang-tidy - bugprone-taxi-async-use-after-free
2+
3+
bugprone-taxi-async-use-after-free
4+
==================================
5+
6+
FIXME: Describe what patterns does the check detect and why. Give examples.

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Clang-Tidy Checks
151151
:doc:`bugprone-swapped-arguments <bugprone/swapped-arguments>`, "Yes"
152152
:doc:`bugprone-switch-missing-default-case <bugprone/switch-missing-default-case>`,
153153
:doc:`bugprone-tagged-union-member-count <bugprone/tagged-union-member-count>`,
154+
:doc:`bugprone-taxi-async-use-after-free <bugprone/taxi-async-use-after-free>`, "Yes"
154155
:doc:`bugprone-terminating-continue <bugprone/terminating-continue>`, "Yes"
155156
:doc:`bugprone-throw-keyword-missing <bugprone/throw-keyword-missing>`,
156157
:doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %check_clang_tidy %s bugprone-taxi-async-use-after-free %t
2+
3+
namespace std {
4+
5+
template<typename T>
6+
class vector {
7+
public:
8+
void push_back(T) {}
9+
};
10+
11+
}
12+
13+
namespace engine {
14+
15+
template <typename Function, typename... Args>
16+
int Async(Function&& f, Args&&... args) {
17+
return 1;
18+
}
19+
20+
}
21+
22+
void f_ok() {
23+
int x = 1;
24+
std::vector<int> v;
25+
26+
v.push_back(engine::Async([&x]{ x = 2;}));
27+
}
28+
29+
void f_use_after_free() {
30+
std::vector<int> v;
31+
int x = 1;
32+
33+
v.push_back(engine::Async([&x]{ x = 2;}));
34+
}
35+

0 commit comments

Comments
 (0)