xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp (revision 6966ac055c3b7a39266fb982493330df7a097997)
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/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14 #include "clang/Basic/Builtins.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 
20 using namespace clang;
21 using namespace ento;
22 
23 namespace {
24 
25 class BuiltinFunctionChecker : public Checker<eval::Call> {
26 public:
27   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
28 };
29 
30 }
31 
32 bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
33                                       CheckerContext &C) const {
34   ProgramStateRef state = C.getState();
35   const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
36   if (!FD)
37     return false;
38 
39   const LocationContext *LCtx = C.getLocationContext();
40   const Expr *CE = Call.getOriginExpr();
41 
42   switch (FD->getBuiltinID()) {
43   default:
44     return false;
45 
46   case Builtin::BI__builtin_assume: {
47     assert (Call.getNumArgs() > 0);
48     SVal Arg = Call.getArgSVal(0);
49     if (Arg.isUndef())
50       return true; // Return true to model purity.
51 
52     state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true);
53     // FIXME: do we want to warn here? Not right now. The most reports might
54     // come from infeasible paths, thus being false positives.
55     if (!state) {
56       C.generateSink(C.getState(), C.getPredecessor());
57       return true;
58     }
59 
60     C.addTransition(state);
61     return true;
62   }
63 
64   case Builtin::BI__builtin_unpredictable:
65   case Builtin::BI__builtin_expect:
66   case Builtin::BI__builtin_assume_aligned:
67   case Builtin::BI__builtin_addressof: {
68     // For __builtin_unpredictable, __builtin_expect, and
69     // __builtin_assume_aligned, just return the value of the subexpression.
70     // __builtin_addressof is going from a reference to a pointer, but those
71     // are represented the same way in the analyzer.
72     assert (Call.getNumArgs() > 0);
73     SVal Arg = Call.getArgSVal(0);
74     C.addTransition(state->BindExpr(CE, LCtx, Arg));
75     return true;
76   }
77 
78   case Builtin::BI__builtin_alloca_with_align:
79   case Builtin::BI__builtin_alloca: {
80     // FIXME: Refactor into StoreManager itself?
81     MemRegionManager& RM = C.getStoreManager().getRegionManager();
82     const AllocaRegion* R =
83       RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
84 
85     // Set the extent of the region in bytes. This enables us to use the
86     // SVal of the argument directly. If we save the extent in bits, we
87     // cannot represent values like symbol*8.
88     auto Size = Call.getArgSVal(0);
89     if (Size.isUndef())
90       return true; // Return true to model purity.
91 
92     SValBuilder& svalBuilder = C.getSValBuilder();
93     DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
94     DefinedOrUnknownSVal extentMatchesSizeArg =
95       svalBuilder.evalEQ(state, Extent, Size.castAs<DefinedOrUnknownSVal>());
96     state = state->assume(extentMatchesSizeArg, true);
97     assert(state && "The region should not have any previous constraints");
98 
99     C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
100     return true;
101   }
102 
103   case Builtin::BI__builtin_dynamic_object_size:
104   case Builtin::BI__builtin_object_size:
105   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     SValBuilder &SVB = C.getSValBuilder();
109     SVal V = UnknownVal();
110     Expr::EvalResult EVResult;
111     if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) {
112       // Make sure the result has the correct type.
113       llvm::APSInt Result = EVResult.Val.getInt();
114       BasicValueFactory &BVF = SVB.getBasicValueFactory();
115       BVF.getAPSIntType(CE->getType()).apply(Result);
116       V = SVB.makeIntVal(Result);
117     }
118 
119     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       if (V.isUnknown())
124         V = SVB.makeIntVal(0, CE->getType());
125     }
126 
127     C.addTransition(state->BindExpr(CE, LCtx, V));
128     return true;
129   }
130   }
131 }
132 
133 void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
134   mgr.registerChecker<BuiltinFunctionChecker>();
135 }
136 
137 bool ento::shouldRegisterBuiltinFunctionChecker(const LangOptions &LO) {
138   return true;
139 }
140