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