1 //== CheckerContext.cpp - Context info for path-sensitive checkers-----------=// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines CheckerContext that provides contextual info for 10 // path-sensitive checkers. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 15 #include "clang/Basic/Builtins.h" 16 #include "clang/Lex/Lexer.h" 17 #include "llvm/ADT/StringExtras.h" 18 19 using namespace clang; 20 using namespace ento; 21 22 const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const { 23 const FunctionDecl *D = CE->getDirectCallee(); 24 if (D) 25 return D; 26 27 const Expr *Callee = CE->getCallee(); 28 SVal L = Pred->getSVal(Callee); 29 return L.getAsFunctionDecl(); 30 } 31 32 StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { 33 if (!FunDecl) 34 return StringRef(); 35 IdentifierInfo *funI = FunDecl->getIdentifier(); 36 if (!funI) 37 return StringRef(); 38 return funI->getName(); 39 } 40 41 StringRef CheckerContext::getDeclDescription(const Decl *D) { 42 if (isa<ObjCMethodDecl, CXXMethodDecl>(D)) 43 return "method"; 44 if (isa<BlockDecl>(D)) 45 return "anonymous block"; 46 return "function"; 47 } 48 49 bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, 50 StringRef Name) { 51 // To avoid false positives (Ex: finding user defined functions with 52 // similar names), only perform fuzzy name matching when it's a builtin. 53 // Using a string compare is slow, we might want to switch on BuiltinID here. 54 unsigned BId = FD->getBuiltinID(); 55 if (BId != 0) { 56 if (Name.empty()) 57 return true; 58 StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId); 59 size_t start = BName.find(Name); 60 if (start != StringRef::npos) { 61 // Accept exact match. 62 if (BName.size() == Name.size()) 63 return true; 64 65 // v-- match starts here 66 // ...xxxxx... 67 // _xxxxx_ 68 // ^ ^ lookbehind and lookahead characters 69 70 const auto MatchPredecessor = [=]() -> bool { 71 return start <= 0 || !llvm::isAlpha(BName[start - 1]); 72 }; 73 const auto MatchSuccessor = [=]() -> bool { 74 std::size_t LookbehindPlace = start + Name.size(); 75 return LookbehindPlace >= BName.size() || 76 !llvm::isAlpha(BName[LookbehindPlace]); 77 }; 78 79 if (MatchPredecessor() && MatchSuccessor()) 80 return true; 81 } 82 } 83 84 const IdentifierInfo *II = FD->getIdentifier(); 85 // If this is a special C++ name without IdentifierInfo, it can't be a 86 // C library function. 87 if (!II) 88 return false; 89 90 // C library functions are either declared directly within a TU (the common 91 // case) or they are accessed through the namespace `std` (when they are used 92 // in C++ via headers like <cstdlib>). 93 const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); 94 if (!(DC->isTranslationUnit() || DC->isStdNamespace())) 95 return false; 96 97 // If this function is not externally visible, it is not a C library function. 98 // Note that we make an exception for inline functions, which may be 99 // declared in header files without external linkage. 100 if (!FD->isInlined() && !FD->isExternallyVisible()) 101 return false; 102 103 if (Name.empty()) 104 return true; 105 106 StringRef FName = II->getName(); 107 if (FName == Name) 108 return true; 109 110 if (FName.starts_with("__inline") && FName.contains(Name)) 111 return true; 112 113 return false; 114 } 115 116 bool CheckerContext::isHardenedVariantOf(const FunctionDecl *FD, 117 StringRef Name) { 118 const IdentifierInfo *II = FD->getIdentifier(); 119 if (!II) 120 return false; 121 122 auto CompletelyMatchesParts = [II](auto... Parts) -> bool { 123 StringRef FName = II->getName(); 124 return (FName.consume_front(Parts) && ...) && FName.empty(); 125 }; 126 127 return CompletelyMatchesParts("__", Name, "_chk") || 128 CompletelyMatchesParts("__builtin_", "__", Name, "_chk"); 129 } 130 131 StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { 132 if (Loc.isMacroID()) 133 return Lexer::getImmediateMacroName(Loc, getSourceManager(), 134 getLangOpts()); 135 SmallString<16> buf; 136 return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); 137 } 138 139 /// Evaluate comparison and return true if it's known that condition is true 140 static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, 141 SVal RHSVal, ProgramStateRef State) { 142 if (LHSVal.isUnknownOrUndef()) 143 return false; 144 ProgramStateManager &Mgr = State->getStateManager(); 145 if (!isa<NonLoc>(LHSVal)) { 146 LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), 147 LHSVal.castAs<Loc>()); 148 if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal)) 149 return false; 150 } 151 152 SValBuilder &Bldr = Mgr.getSValBuilder(); 153 SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, 154 Bldr.getConditionType()); 155 if (Eval.isUnknownOrUndef()) 156 return false; 157 ProgramStateRef StTrue, StFalse; 158 std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); 159 return StTrue && !StFalse; 160 } 161 162 bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { 163 DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); 164 return evalComparison(getSVal(E), BO_GE, V, getState()); 165 } 166 167 bool CheckerContext::isNegative(const Expr *E) { 168 DefinedSVal V = getSValBuilder().makeIntVal(0, false); 169 return evalComparison(getSVal(E), BO_LT, V, getState()); 170 } 171