1 //== CheckerContext.cpp - Context info for path-sensitive checkers-----------=//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines CheckerContext that provides contextual info for
10 // path-sensitive checkers.
12 //===----------------------------------------------------------------------===//
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"
19 using namespace clang
;
22 const FunctionDecl
*CheckerContext::getCalleeDecl(const CallExpr
*CE
) const {
23 const FunctionDecl
*D
= CE
->getDirectCallee();
27 const Expr
*Callee
= CE
->getCallee();
28 SVal L
= Pred
->getSVal(Callee
);
29 return L
.getAsFunctionDecl();
32 StringRef
CheckerContext::getCalleeName(const FunctionDecl
*FunDecl
) const {
35 IdentifierInfo
*funI
= FunDecl
->getIdentifier();
38 return funI
->getName();
41 StringRef
CheckerContext::getDeclDescription(const Decl
*D
) {
42 if (isa
<ObjCMethodDecl
, CXXMethodDecl
>(D
))
44 if (isa
<BlockDecl
>(D
))
45 return "anonymous block";
49 bool CheckerContext::isCLibraryFunction(const FunctionDecl
*FD
,
51 // To avoid false positives (Ex: finding user defined functions with
52 // 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();
58 StringRef 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())
65 // v-- match starts here
68 // ^ ^ lookbehind and lookahead characters
70 const auto MatchPredecessor
= [=]() -> bool {
71 return start
<= 0 || !llvm::isAlpha(BName
[start
- 1]);
73 const auto MatchSuccessor
= [=]() -> bool {
74 std::size_t LookbehindPlace
= start
+ Name
.size();
75 return LookbehindPlace
>= BName
.size() ||
76 !llvm::isAlpha(BName
[LookbehindPlace
]);
79 if (MatchPredecessor() && MatchSuccessor())
84 const IdentifierInfo
*II
= FD
->getIdentifier();
85 // If this is a special C++ name without IdentifierInfo, it can't be a
86 // C library function.
90 // Look through 'extern "C"' and anything similar invented in the future.
91 // If this function is not in TU directly, it is not a C library function.
92 if (!FD
->getDeclContext()->getRedeclContext()->isTranslationUnit())
95 // If this function is not externally visible, it is not a C library function.
96 // Note that we make an exception for inline functions, which may be
97 // declared in header files without external linkage.
98 if (!FD
->isInlined() && !FD
->isExternallyVisible())
104 StringRef FName
= II
->getName();
105 if (FName
.equals(Name
))
108 if (FName
.startswith("__inline") && FName
.contains(Name
))
111 if (FName
.startswith("__") && FName
.endswith("_chk") && FName
.contains(Name
))
117 StringRef
CheckerContext::getMacroNameOrSpelling(SourceLocation
&Loc
) {
119 return Lexer::getImmediateMacroName(Loc
, getSourceManager(),
122 return Lexer::getSpelling(Loc
, buf
, getSourceManager(), getLangOpts());
125 /// Evaluate comparison and return true if it's known that condition is true
126 static bool evalComparison(SVal LHSVal
, BinaryOperatorKind ComparisonOp
,
127 SVal RHSVal
, ProgramStateRef State
) {
128 if (LHSVal
.isUnknownOrUndef())
130 ProgramStateManager
&Mgr
= State
->getStateManager();
131 if (!isa
<NonLoc
>(LHSVal
)) {
132 LHSVal
= Mgr
.getStoreManager().getBinding(State
->getStore(),
133 LHSVal
.castAs
<Loc
>());
134 if (LHSVal
.isUnknownOrUndef() || !isa
<NonLoc
>(LHSVal
))
138 SValBuilder
&Bldr
= Mgr
.getSValBuilder();
139 SVal Eval
= Bldr
.evalBinOp(State
, ComparisonOp
, LHSVal
, RHSVal
,
140 Bldr
.getConditionType());
141 if (Eval
.isUnknownOrUndef())
143 ProgramStateRef StTrue
, StFalse
;
144 std::tie(StTrue
, StFalse
) = State
->assume(Eval
.castAs
<DefinedSVal
>());
145 return StTrue
&& !StFalse
;
148 bool CheckerContext::isGreaterOrEqual(const Expr
*E
, unsigned long long Val
) {
149 DefinedSVal V
= getSValBuilder().makeIntVal(Val
, getASTContext().LongLongTy
);
150 return evalComparison(getSVal(E
), BO_GE
, V
, getState());
153 bool CheckerContext::isNegative(const Expr
*E
) {
154 DefinedSVal V
= getSValBuilder().makeIntVal(0, false);
155 return evalComparison(getSVal(E
), BO_LT
, V
, getState());