-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Feature/labmda uaf #145307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/labmda uaf #145307
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||
| //===--- TaxiAsyncUseAfterFreeCheck.cpp - clang-tidy ----------------------===// | ||||
| // | ||||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
| // See https://llvm.org/LICENSE.txt for license information. | ||||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
| // | ||||
| //===----------------------------------------------------------------------===// | ||||
|
|
||||
| #include "TaxiAsyncUseAfterFreeCheck.h" | ||||
| #include "clang/ASTMatchers/ASTMatchFinder.h" | ||||
|
|
||||
| using namespace clang::ast_matchers; | ||||
|
|
||||
| namespace clang::tidy::bugprone { | ||||
|
|
||||
| void TaxiAsyncUseAfterFreeCheck::registerMatchers(MatchFinder* Finder) { | ||||
| auto hasAsyncName = hasAnyName( | ||||
| "Async", "AsyncNoSpan", "SharedAsyncNoSpan", "CriticalAsyncNoSpan", | ||||
| "SharedCriticalAsyncNoSpan", "CriticalAsync", "SharedCriticalAsync"); | ||||
|
|
||||
| Finder->addMatcher( | ||||
| lambdaExpr( | ||||
| hasParent(materializeTemporaryExpr(hasParent(callExpr( | ||||
| hasParent(cxxMemberCallExpr( | ||||
|
|
||||
| callee(cxxMethodDecl(hasName("push_back"))), | ||||
|
|
||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
| on(declRefExpr(hasDeclaration(varDecl().bind("tasks")))))), | ||||
|
|
||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
| callee(functionDecl(hasAsyncName))))))) | ||||
| .bind("lambda"), | ||||
| this); | ||||
| } | ||||
|
|
||||
| void TaxiAsyncUseAfterFreeCheck::check(const MatchFinder::MatchResult& Result) { | ||||
| const auto* MatchedLambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); | ||||
| const auto* MatchedTasks = Result.Nodes.getNodeAs<VarDecl>("tasks"); | ||||
| const SourceLocation TasksLocation = MatchedTasks->getLocation(); | ||||
|
|
||||
| for (const auto& Capture : MatchedLambda->captures()) { | ||||
| if (!Capture.capturesVariable() || Capture.getCaptureKind() != LCK_ByRef) | ||||
| continue; | ||||
|
|
||||
| const ValueDecl* CapturedVarDecl = Capture.getCapturedVar(); | ||||
| if (CapturedVarDecl->getType().getCanonicalType()->isLValueReferenceType() || | ||||
| CapturedVarDecl->getType().getCanonicalType()->isRValueReferenceType()) { | ||||
| continue; | ||||
| } | ||||
|
|
||||
| if (CapturedVarDecl->getLocation() >= TasksLocation) { | ||||
| diag(Capture.getLocation(), "captured here"); | ||||
| diag(CapturedVarDecl->getLocation(), "variable can be used after free"); | ||||
| diag(TasksLocation, "std::vector<Task> can die after variable"); | ||||
| } | ||||
| } | ||||
| } | ||||
|
|
||||
| } // namespace clang::tidy::bugprone | ||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| //===--- TaxiAsyncUseAfterFreeCheck.h - clang-tidy --------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAXIASYNCUSEAFTERFREECHECK_H | ||
| #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAXIASYNCUSEAFTERFREECHECK_H | ||
|
|
||
| #include "../ClangTidyCheck.h" | ||
|
|
||
| namespace clang::tidy::bugprone { | ||
|
|
||
| /// Use-after-free for engine::Async. | ||
| /// | ||
| /// For the user-facing documentation see: | ||
| /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/taxi-async-use-after-free.html | ||
| class TaxiAsyncUseAfterFreeCheck : public ClangTidyCheck { | ||
| public: | ||
| TaxiAsyncUseAfterFreeCheck(StringRef Name, ClangTidyContext *Context) | ||
| : ClangTidyCheck(Name, Context) {} | ||
| void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||
| void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
| bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { | ||
| return LangOpts.CPlusPlus; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace clang::tidy::bugprone | ||
|
|
||
| #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAXIASYNCUSEAFTERFREECHECK_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -124,6 +124,11 @@ New checks | |
| pointer and store it as class members without handle the copy and move | ||
| constructors and the assignments. | ||
|
|
||
| - New :doc:`bugprone-taxi-async-use-after-free | ||
| <clang-tidy/checks/bugprone/taxi-async-use-after-free>` check. | ||
|
|
||
| Use-after-free for engine::Async. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make it more human-readable. |
||
|
|
||
| - New :doc:`bugprone-unintended-char-ostream-output | ||
| <clang-tidy/checks/bugprone/unintended-char-ostream-output>` check. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| .. title:: clang-tidy - bugprone-taxi-async-use-after-free | ||
|
|
||
| bugprone-taxi-async-use-after-free | ||
| ================================== | ||
|
|
||
| FIXME: Describe what patterns does the check detect and why. Give examples. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing documentation. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // RUN: %check_clang_tidy %s bugprone-taxi-async-use-after-free %t | ||
|
|
||
| namespace std { | ||
|
|
||
| template<typename T> | ||
| class vector { | ||
| public: | ||
| void push_back(T) {} | ||
| }; | ||
|
|
||
| } | ||
|
|
||
| namespace engine { | ||
|
|
||
| template <typename Function, typename... Args> | ||
| int Async(Function&& f, Args&&... args) { | ||
| return 1; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| void f_ok() { | ||
| int x = 1; | ||
| std::vector<int> v; | ||
|
|
||
| v.push_back(engine::Async([&x]{ x = 2;})); | ||
| } | ||
|
|
||
| void f_use_after_free() { | ||
| std::vector<int> v; | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: std::vector<Task> can die after variable [bugprone-taxi-async-use-after-free] | ||
| int x = 1; | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable can be used after free [bugprone-taxi-async-use-after-free] | ||
|
|
||
| v.push_back(engine::Async([&x]{ x = 2;})); | ||
| // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: captured here [bugprone-taxi-async-use-after-free] | ||
| } | ||
|
|
||
| void f_ref() { | ||
| int xx = 1; | ||
| std::vector<int> v; | ||
| int &x = xx; | ||
|
|
||
| v.push_back(engine::Async([&x]{ x = 2;})); | ||
| } | ||
|
|
||
| void f_ref_ref() { | ||
| int xx = 1; | ||
| std::vector<int> v; | ||
| int &&x = static_cast<int&&>(xx); | ||
|
|
||
| v.push_back(engine::Async([&x]{ x = 2;})); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.