1871606d8SAnna Zaks //== CheckerContext.cpp - Context info for path-sensitive checkers-----------=//
2871606d8SAnna Zaks //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6871606d8SAnna Zaks //
7871606d8SAnna Zaks //===----------------------------------------------------------------------===//
8871606d8SAnna Zaks //
9871606d8SAnna Zaks //  This file defines CheckerContext that provides contextual info for
10871606d8SAnna Zaks //  path-sensitive checkers.
11871606d8SAnna Zaks //
12871606d8SAnna Zaks //===----------------------------------------------------------------------===//
13871606d8SAnna Zaks 
14871606d8SAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
155d324e50SAnna Zaks #include "clang/Basic/Builtins.h"
1643de767bSAnna Zaks #include "clang/Lex/Lexer.h"
175d324e50SAnna Zaks 
18871606d8SAnna Zaks using namespace clang;
19871606d8SAnna Zaks using namespace ento;
20871606d8SAnna Zaks 
getCalleeDecl(const CallExpr * CE) const21c6aa531aSAnna Zaks const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
22cc2ef195STomasz Kamiński   const FunctionDecl *D = CE->getDirectCallee();
23cc2ef195STomasz Kamiński   if (D)
24cc2ef195STomasz Kamiński     return D;
25cc2ef195STomasz Kamiński 
26871606d8SAnna Zaks   const Expr *Callee = CE->getCallee();
27d703ec94SGeorge Karpenkov   SVal L = Pred->getSVal(Callee);
28c6aa531aSAnna Zaks   return L.getAsFunctionDecl();
29c6aa531aSAnna Zaks }
30871606d8SAnna Zaks 
getCalleeName(const FunctionDecl * FunDecl) const315d324e50SAnna Zaks StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const {
325d324e50SAnna Zaks   if (!FunDecl)
33871606d8SAnna Zaks     return StringRef();
345d324e50SAnna Zaks   IdentifierInfo *funI = FunDecl->getIdentifier();
35871606d8SAnna Zaks   if (!funI)
36871606d8SAnna Zaks     return StringRef();
37871606d8SAnna Zaks   return funI->getName();
38871606d8SAnna Zaks }
395d324e50SAnna Zaks 
getDeclDescription(const Decl * D)40ad9e7ea6SAnna Zaks StringRef CheckerContext::getDeclDescription(const Decl *D) {
4116be17adSBalazs Benics   if (isa<ObjCMethodDecl, CXXMethodDecl>(D))
42ad9e7ea6SAnna Zaks     return "method";
43ad9e7ea6SAnna Zaks   if (isa<BlockDecl>(D))
44ad9e7ea6SAnna Zaks     return "anonymous block";
45ad9e7ea6SAnna Zaks   return "function";
46ad9e7ea6SAnna Zaks }
475d324e50SAnna Zaks 
isCLibraryFunction(const FunctionDecl * FD,StringRef Name)485d324e50SAnna Zaks bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
495d324e50SAnna Zaks                                         StringRef Name) {
505d324e50SAnna Zaks   // To avoid false positives (Ex: finding user defined functions with
515d324e50SAnna Zaks   // similar names), only perform fuzzy name matching when it's a builtin.
525d324e50SAnna Zaks   // Using a string compare is slow, we might want to switch on BuiltinID here.
535d324e50SAnna Zaks   unsigned BId = FD->getBuiltinID();
545d324e50SAnna Zaks   if (BId != 0) {
55829c3831SJordan Rose     if (Name.empty())
56829c3831SJordan Rose       return true;
5702d5d86bSEric Christopher     StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId);
58abc87369SBalazs Benics     size_t start = BName.find(Name);
59abc87369SBalazs Benics     if (start != StringRef::npos) {
60abc87369SBalazs Benics       // Accept exact match.
61abc87369SBalazs Benics       if (BName.size() == Name.size())
625d324e50SAnna Zaks         return true;
63abc87369SBalazs Benics 
64abc87369SBalazs Benics       //    v-- match starts here
65abc87369SBalazs Benics       // ...xxxxx...
66abc87369SBalazs Benics       //   _xxxxx_
67abc87369SBalazs Benics       //   ^     ^ lookbehind and lookahead characters
68abc87369SBalazs Benics 
69abc87369SBalazs Benics       const auto MatchPredecessor = [=]() -> bool {
70abc87369SBalazs Benics         return start <= 0 || !llvm::isAlpha(BName[start - 1]);
71abc87369SBalazs Benics       };
72abc87369SBalazs Benics       const auto MatchSuccessor = [=]() -> bool {
73abc87369SBalazs Benics         std::size_t LookbehindPlace = start + Name.size();
74abc87369SBalazs Benics         return LookbehindPlace >= BName.size() ||
75abc87369SBalazs Benics                !llvm::isAlpha(BName[LookbehindPlace]);
76abc87369SBalazs Benics       };
77abc87369SBalazs Benics 
78abc87369SBalazs Benics       if (MatchPredecessor() && MatchSuccessor())
79abc87369SBalazs Benics         return true;
80abc87369SBalazs Benics     }
815d324e50SAnna Zaks   }
825d324e50SAnna Zaks 
837aba6368SAnna Zaks   const IdentifierInfo *II = FD->getIdentifier();
847aba6368SAnna Zaks   // If this is a special C++ name without IdentifierInfo, it can't be a
857aba6368SAnna Zaks   // C library function.
867aba6368SAnna Zaks   if (!II)
877aba6368SAnna Zaks     return false;
887aba6368SAnna Zaks 
890da67479SJordan Rose   // Look through 'extern "C"' and anything similar invented in the future.
90be4b2b72SDevin Coughlin   // If this function is not in TU directly, it is not a C library function.
91be4b2b72SDevin Coughlin   if (!FD->getDeclContext()->getRedeclContext()->isTranslationUnit())
920da67479SJordan Rose     return false;
930da67479SJordan Rose 
940da67479SJordan Rose   // If this function is not externally visible, it is not a C library function.
95829c3831SJordan Rose   // Note that we make an exception for inline functions, which may be
96829c3831SJordan Rose   // declared in header files without external linkage.
973ae00052SRafael Espindola   if (!FD->isInlined() && !FD->isExternallyVisible())
980da67479SJordan Rose     return false;
990da67479SJordan Rose 
100829c3831SJordan Rose   if (Name.empty())
101829c3831SJordan Rose     return true;
102829c3831SJordan Rose 
1037aba6368SAnna Zaks   StringRef FName = II->getName();
1046348a810SAnna Zaks   if (FName.equals(Name))
1056348a810SAnna Zaks     return true;
10687b6ff09SAnna Zaks 
1070abb5d29SKazu Hirata   if (FName.startswith("__inline") && FName.contains(Name))
1086348a810SAnna Zaks     return true;
1096348a810SAnna Zaks 
1100abb5d29SKazu Hirata   if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name))
1115d324e50SAnna Zaks     return true;
1125d324e50SAnna Zaks 
1135d324e50SAnna Zaks   return false;
1145d324e50SAnna Zaks }
11543de767bSAnna Zaks 
getMacroNameOrSpelling(SourceLocation & Loc)11643de767bSAnna Zaks StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) {
117e4d798f0SDavid Blaikie   if (Loc.isMacroID())
11843de767bSAnna Zaks     return Lexer::getImmediateMacroName(Loc, getSourceManager(),
119bbafb8a7SDavid Blaikie                                              getLangOpts());
120d44edfc1SNathan James   SmallString<16> buf;
121bbafb8a7SDavid Blaikie   return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts());
12243de767bSAnna Zaks }
12343de767bSAnna Zaks 
124d3d83681SDaniel Marjamaki /// Evaluate comparison and return true if it's known that condition is true
evalComparison(SVal LHSVal,BinaryOperatorKind ComparisonOp,SVal RHSVal,ProgramStateRef State)125d3d83681SDaniel Marjamaki static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp,
126d3d83681SDaniel Marjamaki                            SVal RHSVal, ProgramStateRef State) {
127d3d83681SDaniel Marjamaki   if (LHSVal.isUnknownOrUndef())
128d3d83681SDaniel Marjamaki     return false;
129d3d83681SDaniel Marjamaki   ProgramStateManager &Mgr = State->getStateManager();
130*96ccb690SBalazs Benics   if (!isa<NonLoc>(LHSVal)) {
131d3d83681SDaniel Marjamaki     LHSVal = Mgr.getStoreManager().getBinding(State->getStore(),
132d3d83681SDaniel Marjamaki                                               LHSVal.castAs<Loc>());
133*96ccb690SBalazs Benics     if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal))
134d3d83681SDaniel Marjamaki       return false;
135d3d83681SDaniel Marjamaki   }
136d3d83681SDaniel Marjamaki 
137d3d83681SDaniel Marjamaki   SValBuilder &Bldr = Mgr.getSValBuilder();
138d3d83681SDaniel Marjamaki   SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal,
139d3d83681SDaniel Marjamaki                              Bldr.getConditionType());
140d3d83681SDaniel Marjamaki   if (Eval.isUnknownOrUndef())
141d3d83681SDaniel Marjamaki     return false;
142d3d83681SDaniel Marjamaki   ProgramStateRef StTrue, StFalse;
143d3d83681SDaniel Marjamaki   std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>());
144d3d83681SDaniel Marjamaki   return StTrue && !StFalse;
145d3d83681SDaniel Marjamaki }
146d3d83681SDaniel Marjamaki 
isGreaterOrEqual(const Expr * E,unsigned long long Val)147d3d83681SDaniel Marjamaki bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) {
148d3d83681SDaniel Marjamaki   DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy);
149d3d83681SDaniel Marjamaki   return evalComparison(getSVal(E), BO_GE, V, getState());
150d3d83681SDaniel Marjamaki }
151d3d83681SDaniel Marjamaki 
isNegative(const Expr * E)152d3d83681SDaniel Marjamaki bool CheckerContext::isNegative(const Expr *E) {
153d3d83681SDaniel Marjamaki   DefinedSVal V = getSValBuilder().makeIntVal(0, false);
154d3d83681SDaniel Marjamaki   return evalComparison(getSVal(E), BO_LT, V, getState());
155d3d83681SDaniel Marjamaki }
156