This builtin does not actually evaluate its arguments for side effects, so we shouldn't include them in the CFG. In the analyzer, rely on the constant expression evaluator to get the proper semantics, at least for now. (In the future, we could get ambitious and try to provide path- sensitive size values.) In theory, this does pose a problem for liveness analysis: a variable can be used within the __builtin_object_size argument expression but not show up as live. However, it is very unlikely that such a value would be used to compute the object size and not used to access the object in some way. <rdar://problem/14760817> llvm-svn: 188679
100 lines
3.4 KiB
C++
100 lines
3.4 KiB
C++
//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This checker evaluates clang builtin functions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ClangSACheckers.h"
|
|
#include "clang/Basic/Builtins.h"
|
|
#include "clang/StaticAnalyzer/Core/Checker.h"
|
|
#include "clang/StaticAnalyzer/Core/CheckerManager.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 CallExpr *CE, CheckerContext &C) const;
|
|
};
|
|
|
|
}
|
|
|
|
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
|
|
CheckerContext &C) const {
|
|
ProgramStateRef state = C.getState();
|
|
const FunctionDecl *FD = C.getCalleeDecl(CE);
|
|
const LocationContext *LCtx = C.getLocationContext();
|
|
if (!FD)
|
|
return false;
|
|
|
|
switch (FD->getBuiltinID()) {
|
|
default:
|
|
return false;
|
|
|
|
case Builtin::BI__builtin_expect:
|
|
case Builtin::BI__builtin_addressof: {
|
|
// For __builtin_expect, 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 (CE->arg_begin() != CE->arg_end());
|
|
SVal X = state->getSVal(*(CE->arg_begin()), LCtx);
|
|
C.addTransition(state->BindExpr(CE, LCtx, X));
|
|
return true;
|
|
}
|
|
|
|
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.
|
|
DefinedOrUnknownSVal Size =
|
|
state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>();
|
|
|
|
SValBuilder& svalBuilder = C.getSValBuilder();
|
|
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
|
|
DefinedOrUnknownSVal extentMatchesSizeArg =
|
|
svalBuilder.evalEQ(state, Extent, Size);
|
|
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_object_size: {
|
|
// This must be resolvable at compile time, so we defer to the constant
|
|
// evaluator for a value.
|
|
SVal V = UnknownVal();
|
|
llvm::APSInt Result;
|
|
if (CE->EvaluateAsInt(Result, C.getASTContext(), Expr::SE_NoSideEffects)) {
|
|
// Make sure the result has the correct type.
|
|
SValBuilder &SVB = C.getSValBuilder();
|
|
BasicValueFactory &BVF = SVB.getBasicValueFactory();
|
|
BVF.getAPSIntType(CE->getType()).apply(Result);
|
|
V = SVB.makeIntVal(Result);
|
|
}
|
|
|
|
C.addTransition(state->BindExpr(CE, LCtx, V));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
|
|
mgr.registerChecker<BuiltinFunctionChecker>();
|
|
}
|