xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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