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.startswith("__inline") && FName.contains(Name)) 109 return true; 110 111 if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name)) 112 return true; 113 114 return false; 115 } 116 117 StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { 118 if (Loc.isMacroID()) 119 return Lexer::getImmediateMacroName(Loc, getSourceManager(), 120 getLangOpts()); 121 SmallString<16> buf; 122 return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); 123 } 124 125 /// Evaluate comparison and return true if it's known that condition is true 126 static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, 127 SVal RHSVal, ProgramStateRef State) { 128 if (LHSVal.isUnknownOrUndef()) 129 return false; 130 ProgramStateManager &Mgr = State->getStateManager(); 131 if (!isa<NonLoc>(LHSVal)) { 132 LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), 133 LHSVal.castAs<Loc>()); 134 if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal)) 135 return false; 136 } 137 138 SValBuilder &Bldr = Mgr.getSValBuilder(); 139 SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, 140 Bldr.getConditionType()); 141 if (Eval.isUnknownOrUndef()) 142 return false; 143 ProgramStateRef StTrue, StFalse; 144 std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); 145 return StTrue && !StFalse; 146 } 147 148 bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { 149 DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); 150 return evalComparison(getSVal(E), BO_GE, V, getState()); 151 } 152 153 bool CheckerContext::isNegative(const Expr *E) { 154 DefinedSVal V = getSValBuilder().makeIntVal(0, false); 155 return evalComparison(getSVal(E), BO_LT, V, getState()); 156 } 157