10b57cec5SDimitry Andric //=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This checker evaluates clang builtin functions. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/Basic/Builtins.h" 145ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 150b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 160b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 180b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19*fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace clang; 220b57cec5SDimitry Andric using namespace ento; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace { 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric class BuiltinFunctionChecker : public Checker<eval::Call> { 270b57cec5SDimitry Andric public: 280b57cec5SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 290b57cec5SDimitry Andric }; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric } 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric bool BuiltinFunctionChecker::evalCall(const CallEvent &Call, 340b57cec5SDimitry Andric CheckerContext &C) const { 350b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 360b57cec5SDimitry Andric const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 370b57cec5SDimitry Andric if (!FD) 380b57cec5SDimitry Andric return false; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 410b57cec5SDimitry Andric const Expr *CE = Call.getOriginExpr(); 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric switch (FD->getBuiltinID()) { 440b57cec5SDimitry Andric default: 450b57cec5SDimitry Andric return false; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric case Builtin::BI__builtin_assume: { 480b57cec5SDimitry Andric assert (Call.getNumArgs() > 0); 490b57cec5SDimitry Andric SVal Arg = Call.getArgSVal(0); 500b57cec5SDimitry Andric if (Arg.isUndef()) 510b57cec5SDimitry Andric return true; // Return true to model purity. 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true); 540b57cec5SDimitry Andric // FIXME: do we want to warn here? Not right now. The most reports might 550b57cec5SDimitry Andric // come from infeasible paths, thus being false positives. 560b57cec5SDimitry Andric if (!state) { 570b57cec5SDimitry Andric C.generateSink(C.getState(), C.getPredecessor()); 580b57cec5SDimitry Andric return true; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric C.addTransition(state); 620b57cec5SDimitry Andric return true; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric case Builtin::BI__builtin_unpredictable: 660b57cec5SDimitry Andric case Builtin::BI__builtin_expect: 675ffd83dbSDimitry Andric case Builtin::BI__builtin_expect_with_probability: 680b57cec5SDimitry Andric case Builtin::BI__builtin_assume_aligned: 690b57cec5SDimitry Andric case Builtin::BI__builtin_addressof: { 705ffd83dbSDimitry Andric // For __builtin_unpredictable, __builtin_expect, 715ffd83dbSDimitry Andric // __builtin_expect_with_probability and __builtin_assume_aligned, 725ffd83dbSDimitry Andric // just return the value of the subexpression. 730b57cec5SDimitry Andric // __builtin_addressof is going from a reference to a pointer, but those 740b57cec5SDimitry Andric // are represented the same way in the analyzer. 750b57cec5SDimitry Andric assert (Call.getNumArgs() > 0); 760b57cec5SDimitry Andric SVal Arg = Call.getArgSVal(0); 770b57cec5SDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, Arg)); 780b57cec5SDimitry Andric return true; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric case Builtin::BI__builtin_alloca_with_align: 820b57cec5SDimitry Andric case Builtin::BI__builtin_alloca: { 830b57cec5SDimitry Andric // FIXME: Refactor into StoreManager itself? 840b57cec5SDimitry Andric MemRegionManager& RM = C.getStoreManager().getRegionManager(); 850b57cec5SDimitry Andric const AllocaRegion* R = 860b57cec5SDimitry Andric RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // Set the extent of the region in bytes. This enables us to use the 890b57cec5SDimitry Andric // SVal of the argument directly. If we save the extent in bits, we 900b57cec5SDimitry Andric // cannot represent values like symbol*8. 910b57cec5SDimitry Andric auto Size = Call.getArgSVal(0); 920b57cec5SDimitry Andric if (Size.isUndef()) 930b57cec5SDimitry Andric return true; // Return true to model purity. 940b57cec5SDimitry Andric 95*fe6060f1SDimitry Andric state = setDynamicExtent(state, R, Size.castAs<DefinedOrUnknownSVal>(), 96*fe6060f1SDimitry Andric C.getSValBuilder()); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); 990b57cec5SDimitry Andric return true; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric case Builtin::BI__builtin_dynamic_object_size: 1030b57cec5SDimitry Andric case Builtin::BI__builtin_object_size: 1040b57cec5SDimitry Andric case Builtin::BI__builtin_constant_p: { 1050b57cec5SDimitry Andric // This must be resolvable at compile time, so we defer to the constant 1060b57cec5SDimitry Andric // evaluator for a value. 1070b57cec5SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 1080b57cec5SDimitry Andric SVal V = UnknownVal(); 1090b57cec5SDimitry Andric Expr::EvalResult EVResult; 1100b57cec5SDimitry Andric if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) { 1110b57cec5SDimitry Andric // Make sure the result has the correct type. 1120b57cec5SDimitry Andric llvm::APSInt Result = EVResult.Val.getInt(); 1130b57cec5SDimitry Andric BasicValueFactory &BVF = SVB.getBasicValueFactory(); 1140b57cec5SDimitry Andric BVF.getAPSIntType(CE->getType()).apply(Result); 1150b57cec5SDimitry Andric V = SVB.makeIntVal(Result); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) { 1190b57cec5SDimitry Andric // If we didn't manage to figure out if the value is constant or not, 1200b57cec5SDimitry Andric // it is safe to assume that it's not constant and unsafe to assume 1210b57cec5SDimitry Andric // that it's constant. 1220b57cec5SDimitry Andric if (V.isUnknown()) 1230b57cec5SDimitry Andric V = SVB.makeIntVal(0, CE->getType()); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, V)); 1270b57cec5SDimitry Andric return true; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) { 1330b57cec5SDimitry Andric mgr.registerChecker<BuiltinFunctionChecker>(); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1365ffd83dbSDimitry Andric bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) { 1370b57cec5SDimitry Andric return true; 1380b57cec5SDimitry Andric } 139