diff options
Diffstat (limited to 'clang/lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 108 |
1 files changed, 92 insertions, 16 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 9780a0aba749..4530154ac944 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -16,8 +16,10 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/ParentMap.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" @@ -29,6 +31,7 @@ #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/Analyses/UninitializedValues.h" +#include "clang/Analysis/Analyses/UnsafeBufferUsage.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" @@ -47,6 +50,7 @@ #include <algorithm> #include <deque> #include <iterator> +#include <optional> using namespace clang; @@ -326,7 +330,7 @@ static void visitReachableThrows( if (!Reachable[B->getBlockID()]) continue; for (CFGElement &E : *B) { - Optional<CFGStmt> S = E.getAs<CFGStmt>(); + std::optional<CFGStmt> S = E.getAs<CFGStmt>(); if (!S) continue; if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) @@ -1113,19 +1117,19 @@ namespace { if (!ReachableBlocks.count(P)) { for (const CFGElement &Elem : llvm::reverse(*P)) { - if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) { - if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { - // Don't issue a warning for an unreachable fallthrough - // attribute in template instantiations as it may not be - // unreachable in all instantiations of the template. - if (!IsTemplateInstantiation) - S.Diag(AS->getBeginLoc(), - diag::warn_unreachable_fallthrough_attr); - markFallthroughVisited(AS); - ++AnnotatedCnt; - break; - } - // Don't care about other unreachable statements. + if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) { + if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { + // Don't issue a warning for an unreachable fallthrough + // attribute in template instantiations as it may not be + // unreachable in all instantiations of the template. + if (!IsTemplateInstantiation) + S.Diag(AS->getBeginLoc(), + diag::warn_unreachable_fallthrough_attr); + markFallthroughVisited(AS); + ++AnnotatedCnt; + break; + } + // Don't care about other unreachable statements. } } // If there are no unreachable statements, this may be a special @@ -1198,7 +1202,7 @@ namespace { if (const Stmt *Term = B.getTerminatorStmt()) return Term; for (const CFGElement &Elem : llvm::reverse(B)) - if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) + if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) return CS->getStmt(); // Workaround to detect a statement thrown out by CFGBuilder: // case X: {} case Y: @@ -2139,6 +2143,71 @@ public: } // namespace clang //===----------------------------------------------------------------------===// +// Unsafe buffer usage analysis. +//===----------------------------------------------------------------------===// + +namespace { +class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { + Sema &S; + +public: + UnsafeBufferUsageReporter(Sema &S) : S(S) {} + + void handleUnsafeOperation(const Stmt *Operation, + bool IsRelatedToDecl) override { + SourceLocation Loc; + SourceRange Range; + unsigned MsgParam = 0; + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) { + Loc = ASE->getBase()->getExprLoc(); + Range = ASE->getBase()->getSourceRange(); + MsgParam = 2; + } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) { + BinaryOperator::Opcode Op = BO->getOpcode(); + if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub || + Op == BO_SubAssign) { + if (BO->getRHS()->getType()->isIntegerType()) { + Loc = BO->getLHS()->getExprLoc(); + Range = BO->getLHS()->getSourceRange(); + } else { + Loc = BO->getRHS()->getExprLoc(); + Range = BO->getRHS()->getSourceRange(); + } + MsgParam = 1; + } + } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) { + UnaryOperator::Opcode Op = UO->getOpcode(); + if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc || + Op == UO_PostDec) { + Loc = UO->getSubExpr()->getExprLoc(); + Range = UO->getSubExpr()->getSourceRange(); + MsgParam = 1; + } + } else { + Loc = Operation->getBeginLoc(); + Range = Operation->getSourceRange(); + } + if (IsRelatedToDecl) + S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range; + else + S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range; + } + + // FIXME: rename to handleUnsafeVariable + void handleFixableVariable(const VarDecl *Variable, + FixItList &&Fixes) override { + const auto &D = + S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable); + D << Variable; + D << (Variable->getType()->isPointerType() ? 0 : 1); + D << Variable->getSourceRange(); + for (const auto &F : Fixes) + D << F; + } +}; +} // namespace + +//===----------------------------------------------------------------------===// // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based // warnings on a function, method, or block. //===----------------------------------------------------------------------===// @@ -2269,7 +2338,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( } // Install the logical handler. - llvm::Optional<LogicalErrorHandler> LEH; + std::optional<LogicalErrorHandler> LEH; if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { LEH.emplace(S); AC.getCFGBuildOptions().Observer = &*LEH; @@ -2430,6 +2499,13 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (S.getLangOpts().CPlusPlus && 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); + } + // If none of the previous checks caused a CFG build, trigger one here // for the logical error handler. if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { |