//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This checker evaluates clang builtin functions. // //===----------------------------------------------------------------------===// #include "clang/Basic/Builtins.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" using namespace clang; using namespace ento; namespace { class BuiltinFunctionChecker : public Checker { public: bool evalCall(const CallEvent &Call, CheckerContext &C) const; }; } bool BuiltinFunctionChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef state = C.getState(); const auto *FD = dyn_cast_or_null(Call.getDecl()); if (!FD) return false; const LocationContext *LCtx = C.getLocationContext(); const Expr *CE = Call.getOriginExpr(); switch (FD->getBuiltinID()) { default: return false; case Builtin::BI__builtin_assume: { assert (Call.getNumArgs() > 0); SVal Arg = Call.getArgSVal(0); if (Arg.isUndef()) return true; // Return true to model purity. state = state->assume(Arg.castAs(), true); // FIXME: do we want to warn here? Not right now. The most reports might // come from infeasible paths, thus being false positives. if (!state) { C.generateSink(C.getState(), C.getPredecessor()); return true; } C.addTransition(state); return true; } case Builtin::BI__builtin_unpredictable: case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: case Builtin::BI__builtin_assume_aligned: case Builtin::BI__builtin_addressof: case Builtin::BI__builtin_function_start: { // For __builtin_unpredictable, __builtin_expect, // __builtin_expect_with_probability and __builtin_assume_aligned, // just return the value of the subexpression. // __builtin_addressof is going from a reference to a pointer, but those // are represented the same way in the analyzer. assert (Call.getNumArgs() > 0); SVal Arg = Call.getArgSVal(0); C.addTransition(state->BindExpr(CE, LCtx, Arg)); return true; } case Builtin::BI__builtin_alloca_with_align: case Builtin::BI__builtin_alloca: { SValBuilder &SVB = C.getSValBuilder(); const loc::MemRegionVal R = SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount()); // Set the extent of the region in bytes. This enables us to use the SVal // of the argument directly. If we saved the extent in bits, it'd be more // difficult to reason about values like symbol*8. auto Size = Call.getArgSVal(0); if (auto DefSize = Size.getAs()) { // This `getAs()` is mostly paranoia, because core.CallAndMessage reports // undefined function arguments (unless it's disabled somehow). state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB); } C.addTransition(state->BindExpr(CE, LCtx, R)); return true; } case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: case Builtin::BI__builtin_constant_p: { // This must be resolvable at compile time, so we defer to the constant // evaluator for a value. SValBuilder &SVB = C.getSValBuilder(); SVal V = UnknownVal(); Expr::EvalResult EVResult; if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) { // Make sure the result has the correct type. llvm::APSInt Result = EVResult.Val.getInt(); BasicValueFactory &BVF = SVB.getBasicValueFactory(); BVF.getAPSIntType(CE->getType()).apply(Result); V = SVB.makeIntVal(Result); } if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) { // If we didn't manage to figure out if the value is constant or not, // it is safe to assume that it's not constant and unsafe to assume // that it's constant. if (V.isUnknown()) V = SVB.makeIntVal(0, CE->getType()); } C.addTransition(state->BindExpr(CE, LCtx, V)); return true; } } } void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) { mgr.registerChecker(); } bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) { return true; }