1 //=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This checker evaluates "standalone" clang builtin functions that are not 10 // just special-cased variants of well-known non-builtin functions. 11 // Builtin functions like __builtin_memcpy and __builtin_alloca should be 12 // evaluated by the same checker that handles their non-builtin variant to 13 // ensure that the two variants are handled consistently. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "clang/Basic/Builtins.h" 18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 19 #include "clang/StaticAnalyzer/Core/Checker.h" 20 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 25 26 using namespace clang; 27 using namespace ento; 28 29 namespace { 30 31 class BuiltinFunctionChecker : public Checker<eval::Call> { 32 public: 33 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 34 35 private: 36 // From: clang/include/clang/Basic/Builtins.def 37 // C++ standard library builtins in namespace 'std'. 38 const CallDescriptionSet BuiltinLikeStdFunctions{ 39 {CDM::SimpleFunc, {"std", "addressof"}}, // 40 {CDM::SimpleFunc, {"std", "__addressof"}}, // 41 {CDM::SimpleFunc, {"std", "as_const"}}, // 42 {CDM::SimpleFunc, {"std", "forward"}}, // 43 {CDM::SimpleFunc, {"std", "forward_like"}}, // 44 {CDM::SimpleFunc, {"std", "move"}}, // 45 {CDM::SimpleFunc, {"std", "move_if_noexcept"}}, // 46 }; 47 48 bool isBuiltinLikeFunction(const CallEvent &Call) const; 49 }; 50 51 } // namespace 52 53 bool BuiltinFunctionChecker::isBuiltinLikeFunction( 54 const CallEvent &Call) const { 55 const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 56 if (!FD || FD->getNumParams() != 1) 57 return false; 58 59 if (QualType RetTy = FD->getReturnType(); 60 !RetTy->isPointerType() && !RetTy->isReferenceType()) 61 return false; 62 63 if (QualType ParmTy = FD->getParamDecl(0)->getType(); 64 !ParmTy->isPointerType() && !ParmTy->isReferenceType()) 65 return false; 66 67 return BuiltinLikeStdFunctions.contains(Call); 68 } 69 70 bool BuiltinFunctionChecker::evalCall(const CallEvent &Call, 71 CheckerContext &C) const { 72 ProgramStateRef state = C.getState(); 73 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 74 if (!FD) 75 return false; 76 77 const LocationContext *LCtx = C.getLocationContext(); 78 const Expr *CE = Call.getOriginExpr(); 79 80 if (isBuiltinLikeFunction(Call)) { 81 C.addTransition(state->BindExpr(CE, LCtx, Call.getArgSVal(0))); 82 return true; 83 } 84 85 switch (FD->getBuiltinID()) { 86 default: 87 return false; 88 89 case Builtin::BI__builtin_assume: 90 case Builtin::BI__assume: { 91 assert (Call.getNumArgs() > 0); 92 SVal Arg = Call.getArgSVal(0); 93 if (Arg.isUndef()) 94 return true; // Return true to model purity. 95 96 state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true); 97 // FIXME: do we want to warn here? Not right now. The most reports might 98 // come from infeasible paths, thus being false positives. 99 if (!state) { 100 C.generateSink(C.getState(), C.getPredecessor()); 101 return true; 102 } 103 104 C.addTransition(state); 105 return true; 106 } 107 108 case Builtin::BI__builtin_unpredictable: 109 case Builtin::BI__builtin_expect: 110 case Builtin::BI__builtin_expect_with_probability: 111 case Builtin::BI__builtin_assume_aligned: 112 case Builtin::BI__builtin_addressof: 113 case Builtin::BI__builtin_function_start: { 114 // For __builtin_unpredictable, __builtin_expect, 115 // __builtin_expect_with_probability and __builtin_assume_aligned, 116 // just return the value of the subexpression. 117 // __builtin_addressof is going from a reference to a pointer, but those 118 // are represented the same way in the analyzer. 119 assert (Call.getNumArgs() > 0); 120 SVal Arg = Call.getArgSVal(0); 121 C.addTransition(state->BindExpr(CE, LCtx, Arg)); 122 return true; 123 } 124 125 case Builtin::BI__builtin_dynamic_object_size: 126 case Builtin::BI__builtin_object_size: 127 case Builtin::BI__builtin_constant_p: { 128 // This must be resolvable at compile time, so we defer to the constant 129 // evaluator for a value. 130 SValBuilder &SVB = C.getSValBuilder(); 131 SVal V = UnknownVal(); 132 Expr::EvalResult EVResult; 133 if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) { 134 // Make sure the result has the correct type. 135 llvm::APSInt Result = EVResult.Val.getInt(); 136 BasicValueFactory &BVF = SVB.getBasicValueFactory(); 137 BVF.getAPSIntType(CE->getType()).apply(Result); 138 V = SVB.makeIntVal(Result); 139 } 140 141 if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) { 142 // If we didn't manage to figure out if the value is constant or not, 143 // it is safe to assume that it's not constant and unsafe to assume 144 // that it's constant. 145 if (V.isUnknown()) 146 V = SVB.makeIntVal(0, CE->getType()); 147 } 148 149 C.addTransition(state->BindExpr(CE, LCtx, V)); 150 return true; 151 } 152 } 153 } 154 155 void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) { 156 mgr.registerChecker<BuiltinFunctionChecker>(); 157 } 158 159 bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) { 160 return true; 161 } 162