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