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 18using namespace clang; 19using namespace ento; 20 21const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const { 22 const FunctionDecl *D = CE->getDirectCallee(); 23 if (D) 24 return D; 25 26 const Expr *Callee = CE->getCallee(); 27 SVal L = Pred->getSVal(Callee); 28 return L.getAsFunctionDecl(); 29} 30 31StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { 32 if (!FunDecl) 33 return StringRef(); 34 IdentifierInfo *funI = FunDecl->getIdentifier(); 35 if (!funI) 36 return StringRef(); 37 return funI->getName(); 38} 39 40StringRef CheckerContext::getDeclDescription(const Decl *D) { 41 if (isa<ObjCMethodDecl, CXXMethodDecl>(D)) 42 return "method"; 43 if (isa<BlockDecl>(D)) 44 return "anonymous block"; 45 return "function"; 46} 47 48bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, 49 StringRef Name) { 50 // To avoid false positives (Ex: finding user defined functions with 51 // similar names), only perform fuzzy name matching when it's a builtin. 52 // Using a string compare is slow, we might want to switch on BuiltinID here. 53 unsigned BId = FD->getBuiltinID(); 54 if (BId != 0) { 55 if (Name.empty()) 56 return true; 57 StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId); 58 size_t start = BName.find(Name); 59 if (start != StringRef::npos) { 60 // Accept exact match. 61 if (BName.size() == Name.size()) 62 return true; 63 64 // v-- match starts here 65 // ...xxxxx... 66 // _xxxxx_ 67 // ^ ^ lookbehind and lookahead characters 68 69 const auto MatchPredecessor = [=]() -> bool { 70 return start <= 0 || !llvm::isAlpha(BName[start - 1]); 71 }; 72 const auto MatchSuccessor = [=]() -> bool { 73 std::size_t LookbehindPlace = start + Name.size(); 74 return LookbehindPlace >= BName.size() || 75 !llvm::isAlpha(BName[LookbehindPlace]); 76 }; 77 78 if (MatchPredecessor() && MatchSuccessor()) 79 return true; 80 } 81 } 82 83 const IdentifierInfo *II = FD->getIdentifier(); 84 // If this is a special C++ name without IdentifierInfo, it can't be a 85 // C library function. 86 if (!II) 87 return false; 88 89 // Look through 'extern "C"' and anything similar invented in the future. 90 // If this function is not in TU directly, it is not a C library function. 91 if (!FD->getDeclContext()->getRedeclContext()->isTranslationUnit()) 92 return false; 93 94 // If this function is not externally visible, it is not a C library function. 95 // Note that we make an exception for inline functions, which may be 96 // declared in header files without external linkage. 97 if (!FD->isInlined() && !FD->isExternallyVisible()) 98 return false; 99 100 if (Name.empty()) 101 return true; 102 103 StringRef FName = II->getName(); 104 if (FName.equals(Name)) 105 return true; 106 107 if (FName.startswith("__inline") && FName.contains(Name)) 108 return true; 109 110 if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name)) 111 return true; 112 113 return false; 114} 115 116StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { 117 if (Loc.isMacroID()) 118 return Lexer::getImmediateMacroName(Loc, getSourceManager(), 119 getLangOpts()); 120 SmallString<16> buf; 121 return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); 122} 123 124/// Evaluate comparison and return true if it's known that condition is true 125static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, 126 SVal RHSVal, ProgramStateRef State) { 127 if (LHSVal.isUnknownOrUndef()) 128 return false; 129 ProgramStateManager &Mgr = State->getStateManager(); 130 if (!isa<NonLoc>(LHSVal)) { 131 LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), 132 LHSVal.castAs<Loc>()); 133 if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal)) 134 return false; 135 } 136 137 SValBuilder &Bldr = Mgr.getSValBuilder(); 138 SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, 139 Bldr.getConditionType()); 140 if (Eval.isUnknownOrUndef()) 141 return false; 142 ProgramStateRef StTrue, StFalse; 143 std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); 144 return StTrue && !StFalse; 145} 146 147bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { 148 DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); 149 return evalComparison(getSVal(E), BO_GE, V, getState()); 150} 151 152bool CheckerContext::isNegative(const Expr *E) { 153 DefinedSVal V = getSValBuilder().makeIntVal(0, false); 154 return evalComparison(getSVal(E), BO_LT, V, getState()); 155} 156