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