Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h =================================================================== --- clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" +#include "clang/Sema/Sema.h" namespace clang { @@ -51,10 +52,10 @@ } }; -// This function invokes the analysis and allows the caller to react to it -// through the handler class. -void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, - bool EmitFixits); + +void checkUnsafeBufferUsageForTU(const TranslationUnitDecl *TU, + UnsafeBufferUsageHandler &Handler, + clang::Sema &S, bool EmitFixits); namespace internal { // Tests if any two `FixItHint`s in `FixIts` conflict. Two `FixItHint`s Index: clang/include/clang/Sema/AnalysisBasedWarnings.h =================================================================== --- clang/include/clang/Sema/AnalysisBasedWarnings.h +++ clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H +#include "clang/AST/Decl.h" #include "llvm/ADT/DenseMap.h" #include @@ -95,6 +96,8 @@ void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType); + void CheckUnsafeBufferUsage(const TranslationUnitDecl *D); + Policy getDefaultPolicy() { return DefaultPolicy; } void PrintStats() const; Index: clang/lib/Analysis/UnsafeBufferUsage.cpp =================================================================== --- clang/lib/Analysis/UnsafeBufferUsage.cpp +++ clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -7,10 +7,14 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/UnsafeBufferUsage.h" +#include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Sema.h" #include "llvm/ADT/SmallVector.h" #include #include @@ -1027,7 +1031,7 @@ return S; } -void clang::checkUnsafeBufferUsage(const Decl *D, +void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitFixits) { assert(D && D->getBody()); @@ -1083,3 +1087,56 @@ } } } + +void clang::checkUnsafeBufferUsageForTU(const TranslationUnitDecl *TU, + UnsafeBufferUsageHandler &Handler, + clang::Sema &S, bool EmitFixits) { + DiagnosticsEngine &Diags = S.getDiagnostics(); + static constexpr StringRef Tag = "Callable"; + + struct CallableFinderCallback : MatchFinder::MatchCallback { + UnsafeBufferUsageHandler &Handler; + DiagnosticsEngine &Diags; + clang::Sema &S; + const bool EmitFixits; + + CallableFinderCallback(UnsafeBufferUsageHandler &Handler, + DiagnosticsEngine &Diags, clang::Sema &S, + bool EmitFixits) + : Handler(Handler), Diags(Diags), S(S), EmitFixits(EmitFixits) {} + + void run(const MatchFinder::MatchResult &Result) override { + if (const auto *Callable = Result.Nodes.getNodeAs(Tag)) { + // Do not do any analysis if we are going to just ignore them. + if (Diags.getIgnoreAllWarnings() || + (Diags.getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(Callable->getLocation()))) + return; + + // For code in dependent contexts, we'll do this at instantiation time. + if (cast(Callable)->isDependentContext()) + return; + + if (S.hasUncompilableErrorOccurred()) + return; + + assert (Callable->getBody()); + + // Above checks and early returns are copied from + // `clang::sema::AnalysisBasedWarnings::IssueWarnings`. + checkUnsafeBufferUsage(Callable, Handler, EmitFixits); + } + } + }; + + MatchFinder Finder; + CallableFinderCallback CB(Handler, Diags, S, EmitFixits); + + Finder.addMatcher( + decl(forEachDescendant(decl(anyOf( + functionDecl(hasBody(anything())).bind(Tag), + objcMethodDecl(isDefinition()).bind(Tag), blockDecl().bind(Tag))))), + &CB); + Finder.addMatcher(stmt(forEachDescendant(stmt(lambdaExpr().bind(Tag)))), &CB); + Finder.match(*TU, TU->getASTContext()); +} Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -2290,6 +2291,24 @@ S.Diag(D.Loc, D.PD); } +void clang::sema::AnalysisBasedWarnings::CheckUnsafeBufferUsage( + const TranslationUnitDecl *TU) { + if (!TU) + return; // This is unexpected, give up quietly. + + DiagnosticsEngine &Diags = S.getDiagnostics(); + + // Emit unsafe buffer usage warnings and fixits. + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation())) { + UnsafeBufferUsageReporter R(S); + checkUnsafeBufferUsageForTU( + TU, R, S, + /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits && + S.getLangOpts().CPlusPlus20); + } +} + void clang::sema::AnalysisBasedWarnings::IssueWarnings( sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope, const Decl *D, QualType BlockType) { @@ -2518,16 +2537,6 @@ if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); - // Emit unsafe buffer usage warnings and fixits. - if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) { - UnsafeBufferUsageReporter R(S); - checkUnsafeBufferUsage( - D, R, - /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits && - S.getLangOpts().CPlusPlus20); - } - // If none of the previous checks caused a CFG build, trigger one here // for the logical error handler. if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -1426,6 +1426,8 @@ } } + AnalysisWarnings.CheckUnsafeBufferUsage(Context.getTranslationUnitDecl()); + // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug.