17330f729Sjoerg //=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This checker evaluates clang builtin functions.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Basic/Builtins.h"
14*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
157330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
177330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
187330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
207330f729Sjoerg
217330f729Sjoerg using namespace clang;
227330f729Sjoerg using namespace ento;
237330f729Sjoerg
247330f729Sjoerg namespace {
257330f729Sjoerg
267330f729Sjoerg class BuiltinFunctionChecker : public Checker<eval::Call> {
277330f729Sjoerg public:
287330f729Sjoerg bool evalCall(const CallEvent &Call, CheckerContext &C) const;
297330f729Sjoerg };
307330f729Sjoerg
317330f729Sjoerg }
327330f729Sjoerg
evalCall(const CallEvent & Call,CheckerContext & C) const337330f729Sjoerg bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
347330f729Sjoerg CheckerContext &C) const {
357330f729Sjoerg ProgramStateRef state = C.getState();
367330f729Sjoerg const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
377330f729Sjoerg if (!FD)
387330f729Sjoerg return false;
397330f729Sjoerg
407330f729Sjoerg const LocationContext *LCtx = C.getLocationContext();
417330f729Sjoerg const Expr *CE = Call.getOriginExpr();
427330f729Sjoerg
437330f729Sjoerg switch (FD->getBuiltinID()) {
447330f729Sjoerg default:
457330f729Sjoerg return false;
467330f729Sjoerg
477330f729Sjoerg case Builtin::BI__builtin_assume: {
487330f729Sjoerg assert (Call.getNumArgs() > 0);
497330f729Sjoerg SVal Arg = Call.getArgSVal(0);
507330f729Sjoerg if (Arg.isUndef())
517330f729Sjoerg return true; // Return true to model purity.
527330f729Sjoerg
537330f729Sjoerg state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true);
547330f729Sjoerg // FIXME: do we want to warn here? Not right now. The most reports might
557330f729Sjoerg // come from infeasible paths, thus being false positives.
567330f729Sjoerg if (!state) {
577330f729Sjoerg C.generateSink(C.getState(), C.getPredecessor());
587330f729Sjoerg return true;
597330f729Sjoerg }
607330f729Sjoerg
617330f729Sjoerg C.addTransition(state);
627330f729Sjoerg return true;
637330f729Sjoerg }
647330f729Sjoerg
657330f729Sjoerg case Builtin::BI__builtin_unpredictable:
667330f729Sjoerg case Builtin::BI__builtin_expect:
67*e038c9c4Sjoerg case Builtin::BI__builtin_expect_with_probability:
687330f729Sjoerg case Builtin::BI__builtin_assume_aligned:
697330f729Sjoerg case Builtin::BI__builtin_addressof: {
70*e038c9c4Sjoerg // For __builtin_unpredictable, __builtin_expect,
71*e038c9c4Sjoerg // __builtin_expect_with_probability and __builtin_assume_aligned,
72*e038c9c4Sjoerg // just return the value of the subexpression.
737330f729Sjoerg // __builtin_addressof is going from a reference to a pointer, but those
747330f729Sjoerg // are represented the same way in the analyzer.
757330f729Sjoerg assert (Call.getNumArgs() > 0);
767330f729Sjoerg SVal Arg = Call.getArgSVal(0);
777330f729Sjoerg C.addTransition(state->BindExpr(CE, LCtx, Arg));
787330f729Sjoerg return true;
797330f729Sjoerg }
807330f729Sjoerg
817330f729Sjoerg case Builtin::BI__builtin_alloca_with_align:
827330f729Sjoerg case Builtin::BI__builtin_alloca: {
837330f729Sjoerg // FIXME: Refactor into StoreManager itself?
847330f729Sjoerg MemRegionManager& RM = C.getStoreManager().getRegionManager();
857330f729Sjoerg const AllocaRegion* R =
867330f729Sjoerg RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
877330f729Sjoerg
887330f729Sjoerg // Set the extent of the region in bytes. This enables us to use the
897330f729Sjoerg // SVal of the argument directly. If we save the extent in bits, we
907330f729Sjoerg // cannot represent values like symbol*8.
917330f729Sjoerg auto Size = Call.getArgSVal(0);
927330f729Sjoerg if (Size.isUndef())
937330f729Sjoerg return true; // Return true to model purity.
947330f729Sjoerg
95*e038c9c4Sjoerg state = setDynamicExtent(state, R, Size.castAs<DefinedOrUnknownSVal>(),
96*e038c9c4Sjoerg C.getSValBuilder());
977330f729Sjoerg
987330f729Sjoerg C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
997330f729Sjoerg return true;
1007330f729Sjoerg }
1017330f729Sjoerg
1027330f729Sjoerg case Builtin::BI__builtin_dynamic_object_size:
1037330f729Sjoerg case Builtin::BI__builtin_object_size:
1047330f729Sjoerg case Builtin::BI__builtin_constant_p: {
1057330f729Sjoerg // This must be resolvable at compile time, so we defer to the constant
1067330f729Sjoerg // evaluator for a value.
1077330f729Sjoerg SValBuilder &SVB = C.getSValBuilder();
1087330f729Sjoerg SVal V = UnknownVal();
1097330f729Sjoerg Expr::EvalResult EVResult;
1107330f729Sjoerg if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) {
1117330f729Sjoerg // Make sure the result has the correct type.
1127330f729Sjoerg llvm::APSInt Result = EVResult.Val.getInt();
1137330f729Sjoerg BasicValueFactory &BVF = SVB.getBasicValueFactory();
1147330f729Sjoerg BVF.getAPSIntType(CE->getType()).apply(Result);
1157330f729Sjoerg V = SVB.makeIntVal(Result);
1167330f729Sjoerg }
1177330f729Sjoerg
1187330f729Sjoerg if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) {
1197330f729Sjoerg // If we didn't manage to figure out if the value is constant or not,
1207330f729Sjoerg // it is safe to assume that it's not constant and unsafe to assume
1217330f729Sjoerg // that it's constant.
1227330f729Sjoerg if (V.isUnknown())
1237330f729Sjoerg V = SVB.makeIntVal(0, CE->getType());
1247330f729Sjoerg }
1257330f729Sjoerg
1267330f729Sjoerg C.addTransition(state->BindExpr(CE, LCtx, V));
1277330f729Sjoerg return true;
1287330f729Sjoerg }
1297330f729Sjoerg }
1307330f729Sjoerg }
1317330f729Sjoerg
registerBuiltinFunctionChecker(CheckerManager & mgr)1327330f729Sjoerg void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
1337330f729Sjoerg mgr.registerChecker<BuiltinFunctionChecker>();
1347330f729Sjoerg }
1357330f729Sjoerg
shouldRegisterBuiltinFunctionChecker(const CheckerManager & mgr)136*e038c9c4Sjoerg bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) {
1377330f729Sjoerg return true;
1387330f729Sjoerg }
139