/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===// |
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 checker evaluates clang builtin functions. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "clang/Basic/Builtins.h" |
14 | | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
15 | | #include "clang/StaticAnalyzer/Core/Checker.h" |
16 | | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
17 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
18 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
19 | | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" |
20 | | |
21 | | using namespace clang; |
22 | | using namespace ento; |
23 | | |
24 | | namespace { |
25 | | |
26 | | class BuiltinFunctionChecker : public Checker<eval::Call> { |
27 | | public: |
28 | | bool evalCall(const CallEvent &Call, CheckerContext &C) const; |
29 | | }; |
30 | | |
31 | | } |
32 | | |
33 | | bool BuiltinFunctionChecker::evalCall(const CallEvent &Call, |
34 | 84.7k | CheckerContext &C) const { |
35 | 84.7k | ProgramStateRef state = C.getState(); |
36 | 84.7k | const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); |
37 | 84.7k | if (!FD) |
38 | 222 | return false; |
39 | | |
40 | 84.5k | const LocationContext *LCtx = C.getLocationContext(); |
41 | 84.5k | const Expr *CE = Call.getOriginExpr(); |
42 | | |
43 | 84.5k | switch (FD->getBuiltinID()) { |
44 | 84.4k | default: |
45 | 84.4k | return false; |
46 | | |
47 | 7 | case Builtin::BI__builtin_assume: { |
48 | 7 | assert (Call.getNumArgs() > 0); |
49 | 7 | SVal Arg = Call.getArgSVal(0); |
50 | 7 | if (Arg.isUndef()) |
51 | 0 | return true; // Return true to model purity. |
52 | | |
53 | 7 | state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true); |
54 | | // FIXME: do we want to warn here? Not right now. The most reports might |
55 | | // come from infeasible paths, thus being false positives. |
56 | 7 | if (!state) { |
57 | 2 | C.generateSink(C.getState(), C.getPredecessor()); |
58 | 2 | return true; |
59 | 2 | } |
60 | | |
61 | 5 | C.addTransition(state); |
62 | 5 | return true; |
63 | 7 | } |
64 | | |
65 | 0 | case Builtin::BI__builtin_unpredictable: |
66 | 21 | case Builtin::BI__builtin_expect: |
67 | 21 | case Builtin::BI__builtin_expect_with_probability: |
68 | 25 | case Builtin::BI__builtin_assume_aligned: |
69 | 26 | case Builtin::BI__builtin_addressof: |
70 | 26 | case Builtin::BI__builtin_function_start: { |
71 | | // For __builtin_unpredictable, __builtin_expect, |
72 | | // __builtin_expect_with_probability and __builtin_assume_aligned, |
73 | | // just return the value of the subexpression. |
74 | | // __builtin_addressof is going from a reference to a pointer, but those |
75 | | // are represented the same way in the analyzer. |
76 | 26 | assert (Call.getNumArgs() > 0); |
77 | 26 | SVal Arg = Call.getArgSVal(0); |
78 | 26 | C.addTransition(state->BindExpr(CE, LCtx, Arg)); |
79 | 26 | return true; |
80 | 26 | } |
81 | | |
82 | 0 | case Builtin::BI__builtin_alloca_with_align: |
83 | 93 | case Builtin::BI__builtin_alloca: { |
84 | | // FIXME: Refactor into StoreManager itself? |
85 | 93 | MemRegionManager& RM = C.getStoreManager().getRegionManager(); |
86 | 93 | const AllocaRegion* R = |
87 | 93 | RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); |
88 | | |
89 | | // Set the extent of the region in bytes. This enables us to use the |
90 | | // SVal of the argument directly. If we save the extent in bits, we |
91 | | // cannot represent values like symbol*8. |
92 | 93 | auto Size = Call.getArgSVal(0); |
93 | 93 | if (Size.isUndef()) |
94 | 0 | return true; // Return true to model purity. |
95 | | |
96 | 93 | state = setDynamicExtent(state, R, Size.castAs<DefinedOrUnknownSVal>(), |
97 | 93 | C.getSValBuilder()); |
98 | | |
99 | 93 | C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); |
100 | 93 | return true; |
101 | 93 | } |
102 | | |
103 | 0 | case Builtin::BI__builtin_dynamic_object_size: |
104 | 20 | case Builtin::BI__builtin_object_size: |
105 | 33 | case Builtin::BI__builtin_constant_p: { |
106 | | // This must be resolvable at compile time, so we defer to the constant |
107 | | // evaluator for a value. |
108 | 33 | SValBuilder &SVB = C.getSValBuilder(); |
109 | 33 | SVal V = UnknownVal(); |
110 | 33 | Expr::EvalResult EVResult; |
111 | 33 | if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) { |
112 | | // Make sure the result has the correct type. |
113 | 26 | llvm::APSInt Result = EVResult.Val.getInt(); |
114 | 26 | BasicValueFactory &BVF = SVB.getBasicValueFactory(); |
115 | 26 | BVF.getAPSIntType(CE->getType()).apply(Result); |
116 | 26 | V = SVB.makeIntVal(Result); |
117 | 26 | } |
118 | | |
119 | 33 | if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) { |
120 | | // If we didn't manage to figure out if the value is constant or not, |
121 | | // it is safe to assume that it's not constant and unsafe to assume |
122 | | // that it's constant. |
123 | 13 | if (V.isUnknown()) |
124 | 5 | V = SVB.makeIntVal(0, CE->getType()); |
125 | 13 | } |
126 | | |
127 | 33 | C.addTransition(state->BindExpr(CE, LCtx, V)); |
128 | 33 | return true; |
129 | 20 | } |
130 | 84.5k | } |
131 | 84.5k | } |
132 | | |
133 | 1.28k | void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) { |
134 | 1.28k | mgr.registerChecker<BuiltinFunctionChecker>(); |
135 | 1.28k | } |
136 | | |
137 | 2.57k | bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) { |
138 | 2.57k | return true; |
139 | 2.57k | } |