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