diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp | 139 | 
1 files changed, 139 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp new file mode 100644 index 000000000000..10594e331cbe --- /dev/null +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -0,0 +1,139 @@ +//=== 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/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/Basic/Builtins.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" + +using namespace clang; +using namespace ento; + +namespace { + +class BuiltinFunctionChecker : public Checker<eval::Call> { +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<FunctionDecl>(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<DefinedOrUnknownSVal>(), 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_assume_aligned: +  case Builtin::BI__builtin_addressof: { +    // For __builtin_unpredictable, __builtin_expect, 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: { +    // FIXME: Refactor into StoreManager itself? +    MemRegionManager& RM = C.getStoreManager().getRegionManager(); +    const AllocaRegion* R = +      RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); + +    // Set the extent of the region in bytes. This enables us to use the +    // SVal of the argument directly. If we save the extent in bits, we +    // cannot represent values like symbol*8. +    auto Size = Call.getArgSVal(0); +    if (Size.isUndef()) +      return true; // Return true to model purity. + +    SValBuilder& svalBuilder = C.getSValBuilder(); +    DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); +    DefinedOrUnknownSVal extentMatchesSizeArg = +      svalBuilder.evalEQ(state, Extent, Size.castAs<DefinedOrUnknownSVal>()); +    state = state->assume(extentMatchesSizeArg, true); +    assert(state && "The region should not have any previous constraints"); + +    C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(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<BuiltinFunctionChecker>(); +} + +bool ento::shouldRegisterBuiltinFunctionChecker(const LangOptions &LO) { +  return true; +}  | 
