10b57cec5SDimitry Andric //== CheckerContext.cpp - Context info for path-sensitive checkers-----------=// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines CheckerContext that provides contextual info for 100b57cec5SDimitry Andric // path-sensitive checkers. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 150b57cec5SDimitry Andric #include "clang/Basic/Builtins.h" 160b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 1706c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric using namespace clang; 200b57cec5SDimitry Andric using namespace ento; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const { 23fe6060f1SDimitry Andric const FunctionDecl *D = CE->getDirectCallee(); 24fe6060f1SDimitry Andric if (D) 25fe6060f1SDimitry Andric return D; 26fe6060f1SDimitry Andric 270b57cec5SDimitry Andric const Expr *Callee = CE->getCallee(); 280b57cec5SDimitry Andric SVal L = Pred->getSVal(Callee); 290b57cec5SDimitry Andric return L.getAsFunctionDecl(); 300b57cec5SDimitry Andric } 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { 330b57cec5SDimitry Andric if (!FunDecl) 340b57cec5SDimitry Andric return StringRef(); 350b57cec5SDimitry Andric IdentifierInfo *funI = FunDecl->getIdentifier(); 360b57cec5SDimitry Andric if (!funI) 370b57cec5SDimitry Andric return StringRef(); 380b57cec5SDimitry Andric return funI->getName(); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric StringRef CheckerContext::getDeclDescription(const Decl *D) { 42349cc55cSDimitry Andric if (isa<ObjCMethodDecl, CXXMethodDecl>(D)) 430b57cec5SDimitry Andric return "method"; 440b57cec5SDimitry Andric if (isa<BlockDecl>(D)) 450b57cec5SDimitry Andric return "anonymous block"; 460b57cec5SDimitry Andric return "function"; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, 500b57cec5SDimitry Andric StringRef Name) { 510b57cec5SDimitry Andric // To avoid false positives (Ex: finding user defined functions with 520b57cec5SDimitry Andric // similar names), only perform fuzzy name matching when it's a builtin. 530b57cec5SDimitry Andric // Using a string compare is slow, we might want to switch on BuiltinID here. 540b57cec5SDimitry Andric unsigned BId = FD->getBuiltinID(); 550b57cec5SDimitry Andric if (BId != 0) { 560b57cec5SDimitry Andric if (Name.empty()) 570b57cec5SDimitry Andric return true; 580b57cec5SDimitry Andric StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId); 5981ad6265SDimitry Andric size_t start = BName.find(Name); 6081ad6265SDimitry Andric if (start != StringRef::npos) { 6181ad6265SDimitry Andric // Accept exact match. 6281ad6265SDimitry Andric if (BName.size() == Name.size()) 630b57cec5SDimitry Andric return true; 6481ad6265SDimitry Andric 6581ad6265SDimitry Andric // v-- match starts here 6681ad6265SDimitry Andric // ...xxxxx... 6781ad6265SDimitry Andric // _xxxxx_ 6881ad6265SDimitry Andric // ^ ^ lookbehind and lookahead characters 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric const auto MatchPredecessor = [=]() -> bool { 7181ad6265SDimitry Andric return start <= 0 || !llvm::isAlpha(BName[start - 1]); 7281ad6265SDimitry Andric }; 7381ad6265SDimitry Andric const auto MatchSuccessor = [=]() -> bool { 7481ad6265SDimitry Andric std::size_t LookbehindPlace = start + Name.size(); 7581ad6265SDimitry Andric return LookbehindPlace >= BName.size() || 7681ad6265SDimitry Andric !llvm::isAlpha(BName[LookbehindPlace]); 7781ad6265SDimitry Andric }; 7881ad6265SDimitry Andric 7981ad6265SDimitry Andric if (MatchPredecessor() && MatchSuccessor()) 8081ad6265SDimitry Andric return true; 8181ad6265SDimitry Andric } 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric const IdentifierInfo *II = FD->getIdentifier(); 850b57cec5SDimitry Andric // If this is a special C++ name without IdentifierInfo, it can't be a 860b57cec5SDimitry Andric // C library function. 870b57cec5SDimitry Andric if (!II) 880b57cec5SDimitry Andric return false; 890b57cec5SDimitry Andric 90*0fca6ea1SDimitry Andric // C library functions are either declared directly within a TU (the common 91*0fca6ea1SDimitry Andric // case) or they are accessed through the namespace `std` (when they are used 92*0fca6ea1SDimitry Andric // in C++ via headers like <cstdlib>). 93*0fca6ea1SDimitry Andric const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); 94*0fca6ea1SDimitry Andric if (!(DC->isTranslationUnit() || DC->isStdNamespace())) 950b57cec5SDimitry Andric return false; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric // If this function is not externally visible, it is not a C library function. 980b57cec5SDimitry Andric // Note that we make an exception for inline functions, which may be 990b57cec5SDimitry Andric // declared in header files without external linkage. 1000b57cec5SDimitry Andric if (!FD->isInlined() && !FD->isExternallyVisible()) 1010b57cec5SDimitry Andric return false; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric if (Name.empty()) 1040b57cec5SDimitry Andric return true; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric StringRef FName = II->getName(); 107*0fca6ea1SDimitry Andric if (FName == Name) 1080b57cec5SDimitry Andric return true; 1090b57cec5SDimitry Andric 1105f757f3fSDimitry Andric if (FName.starts_with("__inline") && FName.contains(Name)) 1110b57cec5SDimitry Andric return true; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric return false; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 116*0fca6ea1SDimitry Andric bool CheckerContext::isHardenedVariantOf(const FunctionDecl *FD, 117*0fca6ea1SDimitry Andric StringRef Name) { 118*0fca6ea1SDimitry Andric const IdentifierInfo *II = FD->getIdentifier(); 119*0fca6ea1SDimitry Andric if (!II) 120*0fca6ea1SDimitry Andric return false; 121*0fca6ea1SDimitry Andric 122*0fca6ea1SDimitry Andric auto CompletelyMatchesParts = [II](auto... Parts) -> bool { 123*0fca6ea1SDimitry Andric StringRef FName = II->getName(); 124*0fca6ea1SDimitry Andric return (FName.consume_front(Parts) && ...) && FName.empty(); 125*0fca6ea1SDimitry Andric }; 126*0fca6ea1SDimitry Andric 127*0fca6ea1SDimitry Andric return CompletelyMatchesParts("__", Name, "_chk") || 128*0fca6ea1SDimitry Andric CompletelyMatchesParts("__builtin_", "__", Name, "_chk"); 129*0fca6ea1SDimitry Andric } 130*0fca6ea1SDimitry Andric 1310b57cec5SDimitry Andric StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { 1320b57cec5SDimitry Andric if (Loc.isMacroID()) 1330b57cec5SDimitry Andric return Lexer::getImmediateMacroName(Loc, getSourceManager(), 1340b57cec5SDimitry Andric getLangOpts()); 135e8d8bef9SDimitry Andric SmallString<16> buf; 1360b57cec5SDimitry Andric return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric /// Evaluate comparison and return true if it's known that condition is true 1400b57cec5SDimitry Andric static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, 1410b57cec5SDimitry Andric SVal RHSVal, ProgramStateRef State) { 1420b57cec5SDimitry Andric if (LHSVal.isUnknownOrUndef()) 1430b57cec5SDimitry Andric return false; 1440b57cec5SDimitry Andric ProgramStateManager &Mgr = State->getStateManager(); 14581ad6265SDimitry Andric if (!isa<NonLoc>(LHSVal)) { 1460b57cec5SDimitry Andric LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), 1470b57cec5SDimitry Andric LHSVal.castAs<Loc>()); 14881ad6265SDimitry Andric if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal)) 1490b57cec5SDimitry Andric return false; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric SValBuilder &Bldr = Mgr.getSValBuilder(); 1530b57cec5SDimitry Andric SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, 1540b57cec5SDimitry Andric Bldr.getConditionType()); 1550b57cec5SDimitry Andric if (Eval.isUnknownOrUndef()) 1560b57cec5SDimitry Andric return false; 1570b57cec5SDimitry Andric ProgramStateRef StTrue, StFalse; 1580b57cec5SDimitry Andric std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); 1590b57cec5SDimitry Andric return StTrue && !StFalse; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { 1630b57cec5SDimitry Andric DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); 1640b57cec5SDimitry Andric return evalComparison(getSVal(E), BO_GE, V, getState()); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric bool CheckerContext::isNegative(const Expr *E) { 1680b57cec5SDimitry Andric DefinedSVal V = getSValBuilder().makeIntVal(0, false); 1690b57cec5SDimitry Andric return evalComparison(getSVal(E), BO_LT, V, getState()); 1700b57cec5SDimitry Andric } 171