171 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines CheckerContext that provides contextual info for10// 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 19using namespace clang;20using namespace ento;21 22const 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 32StringRef 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 41StringRef 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 49bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,50 StringRef Name) {51 // To avoid false positives (Ex: finding user defined functions with52 // 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 std::string 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 here66 // ...xxxxx...67 // _xxxxx_68 // ^ ^ lookbehind and lookahead characters69 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 a86 // C library function.87 if (!II)88 return false;89 90 // C library functions are either declared directly within a TU (the common91 // case) or they are accessed through the namespace `std` (when they are used92 // 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 be99 // 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 116bool 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 131StringRef 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 true140static 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 162bool 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 167bool CheckerContext::isNegative(const Expr *E) {168 DefinedSVal V = getSValBuilder().makeIntVal(0, false);169 return evalComparison(getSVal(E), BO_LT, V, getState());170}171