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 // C library functions are either declared directly within a TU (the common
91 // case) or they are accessed through the namespace `std` (when they are used
92 // in C++ via headers like <cstdlib>).
93 const DeclContext
*DC
= FD
->getDeclContext()->getRedeclContext();
94 if (!(DC
->isTranslationUnit() || DC
->isStdNamespace()))
97 // If this function is not externally visible, it is not a C library function.
98 // Note that we make an exception for inline functions, which may be
99 // declared in header files without external linkage.
100 if (!FD
->isInlined() && !FD
->isExternallyVisible())
106 StringRef FName
= II
->getName();
110 if (FName
.starts_with("__inline") && FName
.contains(Name
))
116 bool CheckerContext::isHardenedVariantOf(const FunctionDecl
*FD
,
118 const IdentifierInfo
*II
= FD
->getIdentifier();
122 auto CompletelyMatchesParts
= [II
](auto... Parts
) -> bool {
123 StringRef FName
= II
->getName();
124 return (FName
.consume_front(Parts
) && ...) && FName
.empty();
127 return CompletelyMatchesParts("__", Name
, "_chk") ||
128 CompletelyMatchesParts("__builtin_", "__", Name
, "_chk");
131 StringRef
CheckerContext::getMacroNameOrSpelling(SourceLocation
&Loc
) {
133 return Lexer::getImmediateMacroName(Loc
, getSourceManager(),
136 return Lexer::getSpelling(Loc
, buf
, getSourceManager(), getLangOpts());
139 /// Evaluate comparison and return true if it's known that condition is true
140 static bool evalComparison(SVal LHSVal
, BinaryOperatorKind ComparisonOp
,
141 SVal RHSVal
, ProgramStateRef State
) {
142 if (LHSVal
.isUnknownOrUndef())
144 ProgramStateManager
&Mgr
= State
->getStateManager();
145 if (!isa
<NonLoc
>(LHSVal
)) {
146 LHSVal
= Mgr
.getStoreManager().getBinding(State
->getStore(),
147 LHSVal
.castAs
<Loc
>());
148 if (LHSVal
.isUnknownOrUndef() || !isa
<NonLoc
>(LHSVal
))
152 SValBuilder
&Bldr
= Mgr
.getSValBuilder();
153 SVal Eval
= Bldr
.evalBinOp(State
, ComparisonOp
, LHSVal
, RHSVal
,
154 Bldr
.getConditionType());
155 if (Eval
.isUnknownOrUndef())
157 ProgramStateRef StTrue
, StFalse
;
158 std::tie(StTrue
, StFalse
) = State
->assume(Eval
.castAs
<DefinedSVal
>());
159 return StTrue
&& !StFalse
;
162 bool CheckerContext::isGreaterOrEqual(const Expr
*E
, unsigned long long Val
) {
163 DefinedSVal V
= getSValBuilder().makeIntVal(Val
, getASTContext().LongLongTy
);
164 return evalComparison(getSVal(E
), BO_GE
, V
, getState());
167 bool CheckerContext::isNegative(const Expr
*E
) {
168 DefinedSVal V
= getSValBuilder().makeIntVal(0, false);
169 return evalComparison(getSVal(E
), BO_LT
, V
, getState());