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