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