forked from OSchip/llvm-project
[analyzer][NFC] Merge checkNewAllocator's paramaters into CXXAllocatorCall
Party based on this thread: http://lists.llvm.org/pipermail/cfe-dev/2020-February/064754.html. This patch merges two of CXXAllocatorCall's parameters, so that we are able to supply a CallEvent object to check::NewAllocatorCall (see the description of D75430 to see why this would be great). One of the things mentioned by @NoQ was the following: I think at this point we might actually do a good job sorting out this check::NewAllocator issue because we have a "separate" "Environment" to hold the other SVal, which is "objects under construction"! - so we should probably simply teach CXXAllocatorCall to extract the value from the objects-under-construction trait of the program state and we're good. I had MallocChecker in my crosshair for now, so I admittedly threw together something as a proof of concept. Now that I know that this effort is worth pursuing though, I'll happily look for a solution better then demonstrated in this patch. Differential Revision: https://reviews.llvm.org/D75431
This commit is contained in:
parent
21d2884a9c
commit
f2be30def3
|
@ -285,9 +285,9 @@ public:
|
||||||
|
|
||||||
class NewAllocator {
|
class NewAllocator {
|
||||||
template <typename CHECKER>
|
template <typename CHECKER>
|
||||||
static void _checkNewAllocator(void *checker, const CXXNewExpr *NE,
|
static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call,
|
||||||
SVal Target, CheckerContext &C) {
|
CheckerContext &C) {
|
||||||
((const CHECKER *)checker)->checkNewAllocator(NE, Target, C);
|
((const CHECKER *)checker)->checkNewAllocator(Call, C);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -37,6 +37,7 @@ class TranslationUnitDecl;
|
||||||
namespace ento {
|
namespace ento {
|
||||||
|
|
||||||
class AnalysisManager;
|
class AnalysisManager;
|
||||||
|
class CXXAllocatorCall;
|
||||||
class BugReporter;
|
class BugReporter;
|
||||||
class CallEvent;
|
class CallEvent;
|
||||||
class CheckerBase;
|
class CheckerBase;
|
||||||
|
@ -361,11 +362,9 @@ public:
|
||||||
ExprEngine &Eng);
|
ExprEngine &Eng);
|
||||||
|
|
||||||
/// Run checkers between C++ operator new and constructor calls.
|
/// Run checkers between C++ operator new and constructor calls.
|
||||||
void runCheckersForNewAllocator(const CXXNewExpr *NE, SVal Target,
|
void runCheckersForNewAllocator(const CXXAllocatorCall &Call,
|
||||||
ExplodedNodeSet &Dst,
|
ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
||||||
ExplodedNode *Pred,
|
ExprEngine &Eng, bool wasInlined = false);
|
||||||
ExprEngine &Eng,
|
|
||||||
bool wasInlined = false);
|
|
||||||
|
|
||||||
/// Run checkers for live symbols.
|
/// Run checkers for live symbols.
|
||||||
///
|
///
|
||||||
|
@ -506,7 +505,7 @@ public:
|
||||||
CheckerFn<void (const Stmt *, CheckerContext &)>;
|
CheckerFn<void (const Stmt *, CheckerContext &)>;
|
||||||
|
|
||||||
using CheckNewAllocatorFunc =
|
using CheckNewAllocatorFunc =
|
||||||
CheckerFn<void (const CXXNewExpr *, SVal, CheckerContext &)>;
|
CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>;
|
||||||
|
|
||||||
using CheckDeadSymbolsFunc =
|
using CheckDeadSymbolsFunc =
|
||||||
CheckerFn<void (SymbolReaper &, CheckerContext &)>;
|
CheckerFn<void (SymbolReaper &, CheckerContext &)>;
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/ADT/iterator_range.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
@ -1010,6 +1011,12 @@ public:
|
||||||
return getOriginExpr()->getOperatorNew();
|
return getOriginExpr()->getOperatorNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SVal getObjectUnderConstruction() const {
|
||||||
|
return ExprEngine::getObjectUnderConstruction(getState(), getOriginExpr(),
|
||||||
|
getLocationContext())
|
||||||
|
.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
/// Number of non-placement arguments to the call. It is equal to 2 for
|
/// Number of non-placement arguments to the call. It is equal to 2 for
|
||||||
/// C++17 aligned operator new() calls that have alignment implicitly
|
/// C++17 aligned operator new() calls that have alignment implicitly
|
||||||
/// passed as the second argument, and to 1 for other operator new() calls.
|
/// passed as the second argument, and to 1 for other operator new() calls.
|
||||||
|
|
|
@ -165,7 +165,7 @@ public:
|
||||||
llvm::errs() << "EndAnalysis\n";
|
llvm::errs() << "EndAnalysis\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
|
void checkNewAllocator(const CXXAllocatorCall &Call,
|
||||||
CheckerContext &C) const {
|
CheckerContext &C) const {
|
||||||
if (isCallbackEnabled(C, "NewAllocator"))
|
if (isCallbackEnabled(C, "NewAllocator"))
|
||||||
llvm::errs() << "NewAllocator\n";
|
llvm::errs() << "NewAllocator\n";
|
||||||
|
|
|
@ -315,8 +315,8 @@ public:
|
||||||
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
||||||
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
|
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
|
||||||
void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
|
void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
|
||||||
void checkNewAllocator(const CXXNewExpr *NE, SVal Target,
|
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
|
||||||
CheckerContext &C) const;
|
void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
|
||||||
void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
|
void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
|
||||||
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
|
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
|
||||||
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
||||||
|
@ -1357,11 +1357,12 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MallocChecker::checkNewAllocator(const CXXNewExpr *NE, SVal Target,
|
void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
|
||||||
CheckerContext &C) const {
|
CheckerContext &C) const {
|
||||||
if (!C.wasInlined) {
|
if (!C.wasInlined) {
|
||||||
processNewAllocation(NE, C, Target,
|
processNewAllocation(
|
||||||
(NE->isArray() ? AF_CXXNewArray : AF_CXXNew));
|
Call.getOriginExpr(), C, Call.getObjectUnderConstruction(),
|
||||||
|
(Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
|
||||||
const ObjCMethodCall &msg,
|
const ObjCMethodCall &msg,
|
||||||
ExprEngine &Eng,
|
ExprEngine &Eng,
|
||||||
bool WasInlined) {
|
bool WasInlined) {
|
||||||
auto &checkers = getObjCMessageCheckers(visitKind);
|
const auto &checkers = getObjCMessageCheckers(visitKind);
|
||||||
CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
|
CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
|
||||||
expandGraphWithCheckers(C, Dst, Src);
|
expandGraphWithCheckers(C, Dst, Src);
|
||||||
}
|
}
|
||||||
|
@ -507,35 +507,38 @@ namespace {
|
||||||
using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
|
using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
|
||||||
|
|
||||||
const CheckersTy &Checkers;
|
const CheckersTy &Checkers;
|
||||||
const CXXNewExpr *NE;
|
const CXXAllocatorCall &Call;
|
||||||
SVal Target;
|
|
||||||
bool WasInlined;
|
bool WasInlined;
|
||||||
ExprEngine &Eng;
|
ExprEngine &Eng;
|
||||||
|
|
||||||
CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE,
|
CheckNewAllocatorContext(const CheckersTy &Checkers,
|
||||||
SVal Target, bool WasInlined, ExprEngine &Eng)
|
const CXXAllocatorCall &Call, bool WasInlined,
|
||||||
: Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined),
|
ExprEngine &Eng)
|
||||||
Eng(Eng) {}
|
: Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}
|
||||||
|
|
||||||
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
|
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
|
||||||
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
|
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
|
||||||
|
|
||||||
void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
|
void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
|
||||||
NodeBuilder &Bldr, ExplodedNode *Pred) {
|
NodeBuilder &Bldr, ExplodedNode *Pred) {
|
||||||
ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext());
|
ProgramPoint L =
|
||||||
|
PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext());
|
||||||
CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
|
CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
|
||||||
checkFn(NE, Target, C);
|
checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
|
||||||
|
C);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void CheckerManager::runCheckersForNewAllocator(
|
void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call,
|
||||||
const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
ExplodedNodeSet &Dst,
|
||||||
ExprEngine &Eng, bool WasInlined) {
|
ExplodedNode *Pred,
|
||||||
|
ExprEngine &Eng,
|
||||||
|
bool WasInlined) {
|
||||||
ExplodedNodeSet Src;
|
ExplodedNodeSet Src;
|
||||||
Src.insert(Pred);
|
Src.insert(Pred);
|
||||||
CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng);
|
CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
|
||||||
expandGraphWithCheckers(C, Dst, Src);
|
expandGraphWithCheckers(C, Dst, Src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +654,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
|
||||||
const ExplodedNodeSet &Src,
|
const ExplodedNodeSet &Src,
|
||||||
const CallEvent &Call,
|
const CallEvent &Call,
|
||||||
ExprEngine &Eng) {
|
ExprEngine &Eng) {
|
||||||
for (const auto Pred : Src) {
|
for (auto *const Pred : Src) {
|
||||||
bool anyEvaluated = false;
|
bool anyEvaluated = false;
|
||||||
|
|
||||||
ExplodedNodeSet checkDst;
|
ExplodedNodeSet checkDst;
|
||||||
|
|
|
@ -577,9 +577,10 @@ void ExprEngine::handleConstructor(const Expr *E,
|
||||||
// paths when no-return temporary destructors are used for assertions.
|
// paths when no-return temporary destructors are used for assertions.
|
||||||
const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
|
const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
|
||||||
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
|
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
|
||||||
if (TargetRegion && isa<CXXTempObjectRegion>(TargetRegion) &&
|
if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) &&
|
||||||
cast<CXXConstructorDecl>(Call->getDecl())
|
cast<CXXConstructorDecl>(Call->getDecl())
|
||||||
->getParent()->isAnyDestructorNoReturn()) {
|
->getParent()
|
||||||
|
->isAnyDestructorNoReturn()) {
|
||||||
|
|
||||||
// If we've inlined the constructor, then DstEvaluated would be empty.
|
// If we've inlined the constructor, then DstEvaluated would be empty.
|
||||||
// In this case we still want a sink, which could be implemented
|
// In this case we still want a sink, which could be implemented
|
||||||
|
@ -603,7 +604,7 @@ void ExprEngine::handleConstructor(const Expr *E,
|
||||||
}
|
}
|
||||||
|
|
||||||
ExplodedNodeSet DstPostArgumentCleanup;
|
ExplodedNodeSet DstPostArgumentCleanup;
|
||||||
for (auto I : DstEvaluated)
|
for (ExplodedNode *I : DstEvaluated)
|
||||||
finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
|
finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
|
||||||
|
|
||||||
// If there were other constructors called for object-type arguments
|
// If there were other constructors called for object-type arguments
|
||||||
|
@ -712,7 +713,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
|
||||||
|
|
||||||
ExplodedNodeSet DstPostCall;
|
ExplodedNodeSet DstPostCall;
|
||||||
StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
|
StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
|
||||||
for (auto I : DstPreCall) {
|
for (ExplodedNode *I : DstPreCall) {
|
||||||
// FIXME: Provide evalCall for checkers?
|
// FIXME: Provide evalCall for checkers?
|
||||||
defaultEvalCall(CallBldr, I, *Call);
|
defaultEvalCall(CallBldr, I, *Call);
|
||||||
}
|
}
|
||||||
|
@ -722,7 +723,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
|
||||||
// CXXNewExpr gets processed.
|
// CXXNewExpr gets processed.
|
||||||
ExplodedNodeSet DstPostValue;
|
ExplodedNodeSet DstPostValue;
|
||||||
StmtNodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx);
|
StmtNodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx);
|
||||||
for (auto I : DstPostCall) {
|
for (ExplodedNode *I : DstPostCall) {
|
||||||
// FIXME: Because CNE serves as the "call site" for the allocator (due to
|
// FIXME: Because CNE serves as the "call site" for the allocator (due to
|
||||||
// lack of a better expression in the AST), the conjured return value symbol
|
// lack of a better expression in the AST), the conjured return value symbol
|
||||||
// is going to be of the same type (C++ object pointer type). Technically
|
// is going to be of the same type (C++ object pointer type). Technically
|
||||||
|
@ -756,10 +757,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
|
||||||
ExplodedNodeSet DstPostPostCallCallback;
|
ExplodedNodeSet DstPostPostCallCallback;
|
||||||
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
|
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
|
||||||
DstPostValue, *Call, *this);
|
DstPostValue, *Call, *this);
|
||||||
for (auto I : DstPostPostCallCallback) {
|
for (ExplodedNode *I : DstPostPostCallCallback) {
|
||||||
getCheckerManager().runCheckersForNewAllocator(
|
getCheckerManager().runCheckersForNewAllocator(*Call, Dst, I, *this);
|
||||||
CNE, *getObjectUnderConstruction(I->getState(), CNE, LCtx), Dst, I,
|
|
||||||
*this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
||||||
#include "llvm/ADT/SmallSet.h"
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/Support/Casting.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/SaveAndRestore.h"
|
#include "llvm/Support/SaveAndRestore.h"
|
||||||
|
|
||||||
|
@ -325,17 +326,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
|
||||||
CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
|
CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
|
||||||
|
|
||||||
ExplodedNodeSet DstPostCall;
|
ExplodedNodeSet DstPostCall;
|
||||||
if (const CXXNewExpr *CNE = dyn_cast_or_null<CXXNewExpr>(CE)) {
|
if (llvm::isa_and_nonnull<CXXNewExpr>(CE)) {
|
||||||
ExplodedNodeSet DstPostPostCallCallback;
|
ExplodedNodeSet DstPostPostCallCallback;
|
||||||
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
|
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
|
||||||
CEENode, *UpdatedCall, *this,
|
CEENode, *UpdatedCall, *this,
|
||||||
/*wasInlined=*/true);
|
/*wasInlined=*/true);
|
||||||
for (auto I : DstPostPostCallCallback) {
|
for (ExplodedNode *I : DstPostPostCallCallback) {
|
||||||
getCheckerManager().runCheckersForNewAllocator(
|
getCheckerManager().runCheckersForNewAllocator(
|
||||||
CNE,
|
cast<CXXAllocatorCall>(*UpdatedCall), DstPostCall, I, *this,
|
||||||
*getObjectUnderConstruction(I->getState(), CNE,
|
|
||||||
calleeCtx->getParent()),
|
|
||||||
DstPostCall, I, *this,
|
|
||||||
/*wasInlined=*/true);
|
/*wasInlined=*/true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -591,7 +589,7 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
||||||
// If there were other constructors called for object-type arguments
|
// If there were other constructors called for object-type arguments
|
||||||
// of this call, clean them up.
|
// of this call, clean them up.
|
||||||
ExplodedNodeSet dstArgumentCleanup;
|
ExplodedNodeSet dstArgumentCleanup;
|
||||||
for (auto I : dstCallEvaluated)
|
for (ExplodedNode *I : dstCallEvaluated)
|
||||||
finishArgumentConstruction(dstArgumentCleanup, I, Call);
|
finishArgumentConstruction(dstArgumentCleanup, I, Call);
|
||||||
|
|
||||||
ExplodedNodeSet dstPostCall;
|
ExplodedNodeSet dstPostCall;
|
||||||
|
@ -605,7 +603,7 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
||||||
|
|
||||||
// Run pointerEscape callback with the newly conjured symbols.
|
// Run pointerEscape callback with the newly conjured symbols.
|
||||||
SmallVector<std::pair<SVal, SVal>, 8> Escaped;
|
SmallVector<std::pair<SVal, SVal>, 8> Escaped;
|
||||||
for (auto I : dstPostCall) {
|
for (ExplodedNode *I : dstPostCall) {
|
||||||
NodeBuilder B(I, Dst, *currBldrCtx);
|
NodeBuilder B(I, Dst, *currBldrCtx);
|
||||||
ProgramStateRef State = I->getState();
|
ProgramStateRef State = I->getState();
|
||||||
Escaped.clear();
|
Escaped.clear();
|
||||||
|
@ -743,7 +741,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
|
||||||
const ConstructionContext *CC = CCE ? CCE->getConstructionContext()
|
const ConstructionContext *CC = CCE ? CCE->getConstructionContext()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
||||||
if (CC && isa<NewAllocatedObjectConstructionContext>(CC) &&
|
if (llvm::isa_and_nonnull<NewAllocatedObjectConstructionContext>(CC) &&
|
||||||
!Opts.MayInlineCXXAllocator)
|
!Opts.MayInlineCXXAllocator)
|
||||||
return CIP_DisallowedOnce;
|
return CIP_DisallowedOnce;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue