12754fe60SDimitry Andric //=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric // The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric // This checker evaluates clang builtin functions.
112754fe60SDimitry Andric //
122754fe60SDimitry Andric //===----------------------------------------------------------------------===//
132754fe60SDimitry Andric
14*b5893f02SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15139f7f9bSDimitry Andric #include "clang/Basic/Builtins.h"
163b0f4066SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
173b0f4066SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
183b0f4066SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
192754fe60SDimitry Andric
202754fe60SDimitry Andric using namespace clang;
212754fe60SDimitry Andric using namespace ento;
222754fe60SDimitry Andric
232754fe60SDimitry Andric namespace {
242754fe60SDimitry Andric
253b0f4066SDimitry Andric class BuiltinFunctionChecker : public Checker<eval::Call> {
262754fe60SDimitry Andric public:
273b0f4066SDimitry Andric bool evalCall(const CallExpr *CE, CheckerContext &C) const;
282754fe60SDimitry Andric };
292754fe60SDimitry Andric
302754fe60SDimitry Andric }
312754fe60SDimitry Andric
evalCall(const CallExpr * CE,CheckerContext & C) const323b0f4066SDimitry Andric bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
333b0f4066SDimitry Andric CheckerContext &C) const {
34dff0c46cSDimitry Andric ProgramStateRef state = C.getState();
35dff0c46cSDimitry Andric const FunctionDecl *FD = C.getCalleeDecl(CE);
36dff0c46cSDimitry Andric const LocationContext *LCtx = C.getLocationContext();
372754fe60SDimitry Andric if (!FD)
382754fe60SDimitry Andric return false;
392754fe60SDimitry Andric
40f785676fSDimitry Andric switch (FD->getBuiltinID()) {
41f785676fSDimitry Andric default:
422754fe60SDimitry Andric return false;
432754fe60SDimitry Andric
445517e702SDimitry Andric case Builtin::BI__builtin_assume: {
455517e702SDimitry Andric assert (CE->arg_begin() != CE->arg_end());
464ba319b5SDimitry Andric SVal ArgSVal = C.getSVal(CE->getArg(0));
475517e702SDimitry Andric if (ArgSVal.isUndef())
485517e702SDimitry Andric return true; // Return true to model purity.
495517e702SDimitry Andric
505517e702SDimitry Andric state = state->assume(ArgSVal.castAs<DefinedOrUnknownSVal>(), true);
515517e702SDimitry Andric // FIXME: do we want to warn here? Not right now. The most reports might
525517e702SDimitry Andric // come from infeasible paths, thus being false positives.
53edd7eaddSDimitry Andric if (!state) {
54edd7eaddSDimitry Andric C.generateSink(C.getState(), C.getPredecessor());
555517e702SDimitry Andric return true;
56edd7eaddSDimitry Andric }
575517e702SDimitry Andric
585517e702SDimitry Andric C.addTransition(state);
595517e702SDimitry Andric return true;
605517e702SDimitry Andric }
615517e702SDimitry Andric
620623d748SDimitry Andric case Builtin::BI__builtin_unpredictable:
63f785676fSDimitry Andric case Builtin::BI__builtin_expect:
6439d628a0SDimitry Andric case Builtin::BI__builtin_assume_aligned:
65f785676fSDimitry Andric case Builtin::BI__builtin_addressof: {
660623d748SDimitry Andric // For __builtin_unpredictable, __builtin_expect, and
670623d748SDimitry Andric // __builtin_assume_aligned, just return the value of the subexpression.
68f785676fSDimitry Andric // __builtin_addressof is going from a reference to a pointer, but those
69f785676fSDimitry Andric // are represented the same way in the analyzer.
702754fe60SDimitry Andric assert (CE->arg_begin() != CE->arg_end());
714ba319b5SDimitry Andric SVal X = C.getSVal(*(CE->arg_begin()));
72dff0c46cSDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, X));
732754fe60SDimitry Andric return true;
742754fe60SDimitry Andric }
752754fe60SDimitry Andric
7644290647SDimitry Andric case Builtin::BI__builtin_alloca_with_align:
772754fe60SDimitry Andric case Builtin::BI__builtin_alloca: {
782754fe60SDimitry Andric // FIXME: Refactor into StoreManager itself?
792754fe60SDimitry Andric MemRegionManager& RM = C.getStoreManager().getRegionManager();
802754fe60SDimitry Andric const AllocaRegion* R =
813861d79fSDimitry Andric RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
822754fe60SDimitry Andric
832754fe60SDimitry Andric // Set the extent of the region in bytes. This enables us to use the
842754fe60SDimitry Andric // SVal of the argument directly. If we save the extent in bits, we
852754fe60SDimitry Andric // cannot represent values like symbol*8.
864ba319b5SDimitry Andric auto Size = C.getSVal(*(CE->arg_begin())).castAs<DefinedOrUnknownSVal>();
872754fe60SDimitry Andric
882754fe60SDimitry Andric SValBuilder& svalBuilder = C.getSValBuilder();
892754fe60SDimitry Andric DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
902754fe60SDimitry Andric DefinedOrUnknownSVal extentMatchesSizeArg =
912754fe60SDimitry Andric svalBuilder.evalEQ(state, Extent, Size);
922754fe60SDimitry Andric state = state->assume(extentMatchesSizeArg, true);
93139f7f9bSDimitry Andric assert(state && "The region should not have any previous constraints");
942754fe60SDimitry Andric
95dff0c46cSDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
962754fe60SDimitry Andric return true;
972754fe60SDimitry Andric }
98f785676fSDimitry Andric
994ba319b5SDimitry Andric case Builtin::BI__builtin_object_size:
1004ba319b5SDimitry Andric case Builtin::BI__builtin_constant_p: {
101f785676fSDimitry Andric // This must be resolvable at compile time, so we defer to the constant
102f785676fSDimitry Andric // evaluator for a value.
103f785676fSDimitry Andric SVal V = UnknownVal();
104*b5893f02SDimitry Andric Expr::EvalResult EVResult;
105*b5893f02SDimitry Andric if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) {
106f785676fSDimitry Andric // Make sure the result has the correct type.
107*b5893f02SDimitry Andric llvm::APSInt Result = EVResult.Val.getInt();
108f785676fSDimitry Andric SValBuilder &SVB = C.getSValBuilder();
109f785676fSDimitry Andric BasicValueFactory &BVF = SVB.getBasicValueFactory();
110f785676fSDimitry Andric BVF.getAPSIntType(CE->getType()).apply(Result);
111f785676fSDimitry Andric V = SVB.makeIntVal(Result);
1122754fe60SDimitry Andric }
1132754fe60SDimitry Andric
114f785676fSDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, V));
115f785676fSDimitry Andric return true;
116f785676fSDimitry Andric }
117f785676fSDimitry Andric }
1182754fe60SDimitry Andric }
1193b0f4066SDimitry Andric
registerBuiltinFunctionChecker(CheckerManager & mgr)1203b0f4066SDimitry Andric void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
1213b0f4066SDimitry Andric mgr.registerChecker<BuiltinFunctionChecker>();
1223b0f4066SDimitry Andric }
123