/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //== CheckerContext.cpp - Context info for path-sensitive checkers-----------=// |
2 | | // |
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 |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file defines CheckerContext that provides contextual info for |
10 | | // path-sensitive checkers. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
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" |
18 | | |
19 | | using namespace clang; |
20 | | using namespace ento; |
21 | | |
22 | 99.6k | const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const { |
23 | 99.6k | const FunctionDecl *D = CE->getDirectCallee(); |
24 | 99.6k | if (D) |
25 | 99.0k | return D; |
26 | | |
27 | 622 | const Expr *Callee = CE->getCallee(); |
28 | 622 | SVal L = Pred->getSVal(Callee); |
29 | 622 | return L.getAsFunctionDecl(); |
30 | 99.6k | } |
31 | | |
32 | 57.8k | StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { |
33 | 57.8k | if (!FunDecl) |
34 | 85 | return StringRef(); |
35 | 57.8k | IdentifierInfo *funI = FunDecl->getIdentifier(); |
36 | 57.8k | if (!funI) |
37 | 3.32k | return StringRef(); |
38 | 54.4k | return funI->getName(); |
39 | 57.8k | } |
40 | | |
41 | 32 | StringRef CheckerContext::getDeclDescription(const Decl *D) { |
42 | 32 | if (isa<ObjCMethodDecl, CXXMethodDecl>(D)) |
43 | 6 | return "method"; |
44 | 26 | if (isa<BlockDecl>(D)) |
45 | 0 | return "anonymous block"; |
46 | 26 | return "function"; |
47 | 26 | } |
48 | | |
49 | | bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, |
50 | 898k | StringRef Name) { |
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 | 898k | unsigned BId = FD->getBuiltinID(); |
55 | 898k | if (BId != 0) { |
56 | 98.1k | if (Name.empty()) |
57 | 12.8k | return true; |
58 | 85.3k | StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId); |
59 | 85.3k | size_t start = BName.find(Name); |
60 | 85.3k | if (start != StringRef::npos) { |
61 | | // Accept exact match. |
62 | 2.66k | if (BName.size() == Name.size()) |
63 | 1.63k | return true; |
64 | | |
65 | | // v-- match starts here |
66 | | // ...xxxxx... |
67 | | // _xxxxx_ |
68 | | // ^ ^ lookbehind and lookahead characters |
69 | | |
70 | 1.03k | const auto MatchPredecessor = [=]() -> bool { |
71 | 1.03k | return start <= 0 || !llvm::isAlpha(BName[start - 1]); |
72 | 1.03k | }; |
73 | 1.03k | const auto MatchSuccessor = [=]() -> bool { |
74 | 954 | std::size_t LookbehindPlace = start + Name.size(); |
75 | 954 | return LookbehindPlace >= BName.size() || |
76 | 954 | !llvm::isAlpha(BName[LookbehindPlace])219 ; |
77 | 954 | }; |
78 | | |
79 | 1.03k | if (MatchPredecessor() && MatchSuccessor()954 ) |
80 | 954 | return true; |
81 | 1.03k | } |
82 | 85.3k | } |
83 | | |
84 | 883k | const IdentifierInfo *II = FD->getIdentifier(); |
85 | | // If this is a special C++ name without IdentifierInfo, it can't be a |
86 | | // C library function. |
87 | 883k | if (!II) |
88 | 69.3k | return false; |
89 | | |
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 | 814k | if (!FD->getDeclContext()->getRedeclContext()->isTranslationUnit()) |
93 | 145k | return false; |
94 | | |
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 | 668k | if (!FD->isInlined() && !FD->isExternallyVisible()638k ) |
99 | 7.00k | return false; |
100 | | |
101 | 661k | if (Name.empty()) |
102 | 59.0k | return true; |
103 | | |
104 | 602k | StringRef FName = II->getName(); |
105 | 602k | if (FName.equals(Name)) |
106 | 351 | return true; |
107 | | |
108 | 602k | if (FName.startswith("__inline") && FName.contains(Name)17 ) |
109 | 1 | return true; |
110 | | |
111 | 602k | if (FName.startswith("__") && FName.endswith("_chk")26.0k && FName.contains(Name)3.84k ) |
112 | 139 | return true; |
113 | | |
114 | 602k | return false; |
115 | 602k | } |
116 | | |
117 | 35 | StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) { |
118 | 35 | if (Loc.isMacroID()) |
119 | 30 | return Lexer::getImmediateMacroName(Loc, getSourceManager(), |
120 | 30 | getLangOpts()); |
121 | 5 | SmallString<16> buf; |
122 | 5 | return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts()); |
123 | 35 | } |
124 | | |
125 | | /// Evaluate comparison and return true if it's known that condition is true |
126 | | static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp, |
127 | 483 | SVal RHSVal, ProgramStateRef State) { |
128 | 483 | if (LHSVal.isUnknownOrUndef()) |
129 | 6 | return false; |
130 | 477 | ProgramStateManager &Mgr = State->getStateManager(); |
131 | 477 | if (!isa<NonLoc>(LHSVal)) { |
132 | 6 | LHSVal = Mgr.getStoreManager().getBinding(State->getStore(), |
133 | 6 | LHSVal.castAs<Loc>()); |
134 | 6 | if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal)) |
135 | 0 | return false; |
136 | 6 | } |
137 | | |
138 | 477 | SValBuilder &Bldr = Mgr.getSValBuilder(); |
139 | 477 | SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal, |
140 | 477 | Bldr.getConditionType()); |
141 | 477 | if (Eval.isUnknownOrUndef()) |
142 | 0 | return false; |
143 | 477 | ProgramStateRef StTrue, StFalse; |
144 | 477 | std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>()); |
145 | 477 | return StTrue && !StFalse259 ; |
146 | 477 | } |
147 | | |
148 | 265 | bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) { |
149 | 265 | DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy); |
150 | 265 | return evalComparison(getSVal(E), BO_GE, V, getState()); |
151 | 265 | } |
152 | | |
153 | 218 | bool CheckerContext::isNegative(const Expr *E) { |
154 | 218 | DefinedSVal V = getSValBuilder().makeIntVal(0, false); |
155 | 218 | return evalComparison(getSVal(E), BO_LT, V, getState()); |
156 | 218 | } |