diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index ff8037e592b..7c53b2d21a5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -43,6 +43,8 @@ class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols, void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const; void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const; void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const; + void analyzerDenote(const CallExpr *CE, CheckerContext &C) const; + void analyzerExpress(const CallExpr *CE, CheckerContext &C) const; typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, CheckerContext &C) const; @@ -60,6 +62,7 @@ public: } REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef) +REGISTER_MAP_WITH_PROGRAMSTATE(DenotedSymbols, SymbolRef, const StringLiteral *) bool ExprInspectionChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { @@ -82,6 +85,8 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE, .Case("clang_analyzer_numTimesReached", &ExprInspectionChecker::analyzerNumTimesReached) .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump) + .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote) + .Case("clang_analyzer_express", &ExprInspectionChecker::analyzerExpress) .Default(nullptr); if (!Handler) @@ -264,6 +269,13 @@ void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper, N = BugNode; State = State->remove<MarkedSymbols>(Sym); } + + for (auto I : State->get<DenotedSymbols>()) { + SymbolRef Sym = I.first; + if (!SymReaper.isLive(Sym)) + State = State->remove<DenotedSymbols>(Sym); + } + C.addTransition(State, N); } @@ -295,6 +307,92 @@ void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE, reportBug(HashContent, C); } +void ExprInspectionChecker::analyzerDenote(const CallExpr *CE, + CheckerContext &C) const { + if (CE->getNumArgs() < 2) { + reportBug("clang_analyzer_denote() requires a symbol and a string literal", + C); + return; + } + + SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); + if (!Sym) { + reportBug("Not a symbol", C); + return; + } + + if (!isa<SymbolData>(Sym)) { + reportBug("Not an atomic symbol", C); + return; + } + + const auto *E = dyn_cast<StringLiteral>(CE->getArg(1)->IgnoreParenCasts()); + if (!E) { + reportBug("Not a string literal", C); + return; + } + + ProgramStateRef State = C.getState(); + + C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E)); +} + +class SymbolExpressor + : public SymExprVisitor<SymbolExpressor, Optional<std::string>> { + ProgramStateRef State; + +public: + SymbolExpressor(ProgramStateRef State) : State(State) {} + + Optional<std::string> VisitSymExpr(const SymExpr *S) { + if (const StringLiteral *const *SLPtr = State->get<DenotedSymbols>(S)) { + const StringLiteral *SL = *SLPtr; + return std::string(SL->getBytes()); + } + return None; + } + + Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) { + if (auto Str = Visit(S->getLHS())) + return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " + + std::to_string(S->getRHS().getLimitedValue()) + + (S->getRHS().isUnsigned() ? "U" : "")) + .str(); + return None; + } + + Optional<std::string> VisitSymSymExpr(const SymSymExpr *S) { + if (auto Str1 = Visit(S->getLHS())) + if (auto Str2 = Visit(S->getRHS())) + return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + + " " + *Str2).str(); + return None; + } +}; + +void ExprInspectionChecker::analyzerExpress(const CallExpr *CE, + CheckerContext &C) const { + if (CE->getNumArgs() == 0) { + reportBug("clang_analyzer_express() requires a symbol", C); + return; + } + + SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); + if (!Sym) { + reportBug("Not a symbol", C); + return; + } + + SymbolExpressor V(C.getState()); + auto Str = V.Visit(Sym); + if (!Str) { + reportBug("Unable to express", C); + return; + } + + reportBug(*Str, C); +} + void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Mgr.registerChecker<ExprInspectionChecker>(); } |