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