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 //
9*0fca6ea1SDimitry Andric // This checker evaluates "standalone" clang builtin functions that are not
10*0fca6ea1SDimitry Andric // just special-cased variants of well-known non-builtin functions.
11*0fca6ea1SDimitry Andric // Builtin functions like __builtin_memcpy and __builtin_alloca should be
12*0fca6ea1SDimitry Andric // evaluated by the same checker that handles their non-builtin variant to
13*0fca6ea1SDimitry Andric // ensure that the two variants are handled consistently.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #include "clang/Basic/Builtins.h"
185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
190b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21*0fca6ea1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
220b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric using namespace clang;
270b57cec5SDimitry Andric using namespace ento;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric namespace {
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric class BuiltinFunctionChecker : public Checker<eval::Call> {
320b57cec5SDimitry Andric public:
330b57cec5SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const;
34*0fca6ea1SDimitry Andric
35*0fca6ea1SDimitry Andric private:
36*0fca6ea1SDimitry Andric // From: clang/include/clang/Basic/Builtins.def
37*0fca6ea1SDimitry Andric // C++ standard library builtins in namespace 'std'.
38*0fca6ea1SDimitry Andric const CallDescriptionSet BuiltinLikeStdFunctions{
39*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "addressof"}}, //
40*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "__addressof"}}, //
41*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "as_const"}}, //
42*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "forward"}}, //
43*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "forward_like"}}, //
44*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "move"}}, //
45*0fca6ea1SDimitry Andric {CDM::SimpleFunc, {"std", "move_if_noexcept"}}, //
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric
48*0fca6ea1SDimitry Andric bool isBuiltinLikeFunction(const CallEvent &Call) const;
49*0fca6ea1SDimitry Andric };
50*0fca6ea1SDimitry Andric
51*0fca6ea1SDimitry Andric } // namespace
52*0fca6ea1SDimitry Andric
isBuiltinLikeFunction(const CallEvent & Call) const53*0fca6ea1SDimitry Andric bool BuiltinFunctionChecker::isBuiltinLikeFunction(
54*0fca6ea1SDimitry Andric const CallEvent &Call) const {
55*0fca6ea1SDimitry Andric const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(Call.getDecl());
56*0fca6ea1SDimitry Andric if (!FD || FD->getNumParams() != 1)
57*0fca6ea1SDimitry Andric return false;
58*0fca6ea1SDimitry Andric
59*0fca6ea1SDimitry Andric if (QualType RetTy = FD->getReturnType();
60*0fca6ea1SDimitry Andric !RetTy->isPointerType() && !RetTy->isReferenceType())
61*0fca6ea1SDimitry Andric return false;
62*0fca6ea1SDimitry Andric
63*0fca6ea1SDimitry Andric if (QualType ParmTy = FD->getParamDecl(0)->getType();
64*0fca6ea1SDimitry Andric !ParmTy->isPointerType() && !ParmTy->isReferenceType())
65*0fca6ea1SDimitry Andric return false;
66*0fca6ea1SDimitry Andric
67*0fca6ea1SDimitry Andric return BuiltinLikeStdFunctions.contains(Call);
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric
evalCall(const CallEvent & Call,CheckerContext & C) const700b57cec5SDimitry Andric bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
710b57cec5SDimitry Andric CheckerContext &C) const {
720b57cec5SDimitry Andric ProgramStateRef state = C.getState();
730b57cec5SDimitry Andric const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
740b57cec5SDimitry Andric if (!FD)
750b57cec5SDimitry Andric return false;
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext();
780b57cec5SDimitry Andric const Expr *CE = Call.getOriginExpr();
790b57cec5SDimitry Andric
80*0fca6ea1SDimitry Andric if (isBuiltinLikeFunction(Call)) {
81*0fca6ea1SDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, Call.getArgSVal(0)));
82*0fca6ea1SDimitry Andric return true;
83*0fca6ea1SDimitry Andric }
84*0fca6ea1SDimitry Andric
850b57cec5SDimitry Andric switch (FD->getBuiltinID()) {
860b57cec5SDimitry Andric default:
870b57cec5SDimitry Andric return false;
880b57cec5SDimitry Andric
89*0fca6ea1SDimitry Andric case Builtin::BI__builtin_assume:
90*0fca6ea1SDimitry Andric case Builtin::BI__assume: {
910b57cec5SDimitry Andric assert (Call.getNumArgs() > 0);
920b57cec5SDimitry Andric SVal Arg = Call.getArgSVal(0);
930b57cec5SDimitry Andric if (Arg.isUndef())
940b57cec5SDimitry Andric return true; // Return true to model purity.
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric state = state->assume(Arg.castAs<DefinedOrUnknownSVal>(), true);
970b57cec5SDimitry Andric // FIXME: do we want to warn here? Not right now. The most reports might
980b57cec5SDimitry Andric // come from infeasible paths, thus being false positives.
990b57cec5SDimitry Andric if (!state) {
1000b57cec5SDimitry Andric C.generateSink(C.getState(), C.getPredecessor());
1010b57cec5SDimitry Andric return true;
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric C.addTransition(state);
1050b57cec5SDimitry Andric return true;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric case Builtin::BI__builtin_unpredictable:
1090b57cec5SDimitry Andric case Builtin::BI__builtin_expect:
1105ffd83dbSDimitry Andric case Builtin::BI__builtin_expect_with_probability:
1110b57cec5SDimitry Andric case Builtin::BI__builtin_assume_aligned:
1120eae32dcSDimitry Andric case Builtin::BI__builtin_addressof:
1130eae32dcSDimitry Andric case Builtin::BI__builtin_function_start: {
1145ffd83dbSDimitry Andric // For __builtin_unpredictable, __builtin_expect,
1155ffd83dbSDimitry Andric // __builtin_expect_with_probability and __builtin_assume_aligned,
1165ffd83dbSDimitry Andric // just return the value of the subexpression.
1170b57cec5SDimitry Andric // __builtin_addressof is going from a reference to a pointer, but those
1180b57cec5SDimitry Andric // are represented the same way in the analyzer.
1190b57cec5SDimitry Andric assert (Call.getNumArgs() > 0);
1200b57cec5SDimitry Andric SVal Arg = Call.getArgSVal(0);
1210b57cec5SDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, Arg));
1220b57cec5SDimitry Andric return true;
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric case Builtin::BI__builtin_dynamic_object_size:
1260b57cec5SDimitry Andric case Builtin::BI__builtin_object_size:
1270b57cec5SDimitry Andric case Builtin::BI__builtin_constant_p: {
1280b57cec5SDimitry Andric // This must be resolvable at compile time, so we defer to the constant
1290b57cec5SDimitry Andric // evaluator for a value.
1300b57cec5SDimitry Andric SValBuilder &SVB = C.getSValBuilder();
1310b57cec5SDimitry Andric SVal V = UnknownVal();
1320b57cec5SDimitry Andric Expr::EvalResult EVResult;
1330b57cec5SDimitry Andric if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) {
1340b57cec5SDimitry Andric // Make sure the result has the correct type.
1350b57cec5SDimitry Andric llvm::APSInt Result = EVResult.Val.getInt();
1360b57cec5SDimitry Andric BasicValueFactory &BVF = SVB.getBasicValueFactory();
1370b57cec5SDimitry Andric BVF.getAPSIntType(CE->getType()).apply(Result);
1380b57cec5SDimitry Andric V = SVB.makeIntVal(Result);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) {
1420b57cec5SDimitry Andric // If we didn't manage to figure out if the value is constant or not,
1430b57cec5SDimitry Andric // it is safe to assume that it's not constant and unsafe to assume
1440b57cec5SDimitry Andric // that it's constant.
1450b57cec5SDimitry Andric if (V.isUnknown())
1460b57cec5SDimitry Andric V = SVB.makeIntVal(0, CE->getType());
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
1490b57cec5SDimitry Andric C.addTransition(state->BindExpr(CE, LCtx, V));
1500b57cec5SDimitry Andric return true;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
registerBuiltinFunctionChecker(CheckerManager & mgr)1550b57cec5SDimitry Andric void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
1560b57cec5SDimitry Andric mgr.registerChecker<BuiltinFunctionChecker>();
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
shouldRegisterBuiltinFunctionChecker(const CheckerManager & mgr)1595ffd83dbSDimitry Andric bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) {
1600b57cec5SDimitry Andric return true;
1610b57cec5SDimitry Andric }
162