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 // Look through 'extern "C"' and anything similar invented in the future. 91 // If this function is not in TU directly, it is not a C library function. 92 if (!FD->getDeclContext()->getRedeclContext()->isTranslationUnit()) 93 return false; 94 95 // If this function is not externally visible, it is not a C library function. 96 // Note that we make an exception for inline functions, which may be 97 // declared in header files without external linkage. 98 if (!FD->isInlined() && !FD->isExternallyVisible()) 99 return false; 100 101 if (Name.empty()) 102 return true; 103 104 StringRef FName = II->getName(); 105 if (FName.equals(Name)) 106 return true; 107 108 if (FName.starts_with("__inline") && FName.contains(Name)) 109 return true; 110 111 if (FName.starts_with("__") && FName.ends_with("_chk") && 112 FName.contains(Name)) 113 return true; 114 115 return false; 116 } 117 118 StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { 119 if (Loc.isMacroID()) 120 return Lexer::getImmediateMacroName(Loc, getSourceManager(), 121 getLangOpts()); 122 SmallString<16> buf; 123 return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); 124 } 125 126 /// Evaluate comparison and return true if it's known that condition is true 127 static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, 128 SVal RHSVal, ProgramStateRef State) { 129 if (LHSVal.isUnknownOrUndef()) 130 return false; 131 ProgramStateManager &Mgr = State->getStateManager(); 132 if (!isa<NonLoc>(LHSVal)) { 133 LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), 134 LHSVal.castAs<Loc>()); 135 if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal)) 136 return false; 137 } 138 139 SValBuilder &Bldr = Mgr.getSValBuilder(); 140 SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, 141 Bldr.getConditionType()); 142 if (Eval.isUnknownOrUndef()) 143 return false; 144 ProgramStateRef StTrue, StFalse; 145 std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); 146 return StTrue && !StFalse; 147 } 148 149 bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { 150 DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); 151 return evalComparison(getSVal(E), BO_GE, V, getState()); 152 } 153 154 bool CheckerContext::isNegative(const Expr *E) { 155 DefinedSVal V = getSValBuilder().makeIntVal(0, false); 156 return evalComparison(getSVal(E), BO_LT, V, getState()); 157 } 158