Skip to content

Commit

Permalink
[analyzer][NFC] Merge checkNewAllocator's paramaters into CXXAllocato…
Browse files Browse the repository at this point in the history
…rCall

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
  • Loading branch information
Szelethus committed May 19, 2020
1 parent 21d2884 commit f2be30d
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 47 deletions.
6 changes: 3 additions & 3 deletions clang/include/clang/StaticAnalyzer/Core/Checker.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,9 @@ class BranchCondition {

class NewAllocator {
template <typename CHECKER>
static void _checkNewAllocator(void *checker, const CXXNewExpr *NE,
SVal Target, CheckerContext &C) {
((const CHECKER *)checker)->checkNewAllocator(NE, Target, C);
static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call,
CheckerContext &C) {
((const CHECKER *)checker)->checkNewAllocator(Call, C);
}

public:
Expand Down
11 changes: 5 additions & 6 deletions clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class TranslationUnitDecl;
namespace ento {

class AnalysisManager;
class CXXAllocatorCall;
class BugReporter;
class CallEvent;
class CheckerBase;
Expand Down Expand Up @@ -361,11 +362,9 @@ class CheckerManager {
ExprEngine &Eng);

/// Run checkers between C++ operator new and constructor calls.
void runCheckersForNewAllocator(const CXXNewExpr *NE, SVal Target,
ExplodedNodeSet &Dst,
ExplodedNode *Pred,
ExprEngine &Eng,
bool wasInlined = false);
void runCheckersForNewAllocator(const CXXAllocatorCall &Call,
ExplodedNodeSet &Dst, ExplodedNode *Pred,
ExprEngine &Eng, bool wasInlined = false);

/// Run checkers for live symbols.
///
Expand Down Expand Up @@ -506,7 +505,7 @@ class CheckerManager {
CheckerFn<void (const Stmt *, CheckerContext &)>;

using CheckNewAllocatorFunc =
CheckerFn<void (const CXXNewExpr *, SVal, CheckerContext &)>;
CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>;

using CheckDeadSymbolsFunc =
CheckerFn<void (SymbolReaper &, CheckerContext &)>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -1010,6 +1011,12 @@ class CXXAllocatorCall : public AnyFunctionCall {
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
/// C++17 aligned operator new() calls that have alignment implicitly
/// passed as the second argument, and to 1 for other operator new() calls.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class AnalysisOrderChecker
llvm::errs() << "EndAnalysis\n";
}

void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
void checkNewAllocator(const CXXAllocatorCall &Call,
CheckerContext &C) const {
if (isCallbackEnabled(C, "NewAllocator"))
llvm::errs() << "NewAllocator\n";
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ class MallocChecker
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
void checkNewAllocator(const CXXNewExpr *NE, SVal Target,
CheckerContext &C) const;
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
Expand Down Expand Up @@ -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 {
if (!C.wasInlined) {
processNewAllocation(NE, C, Target,
(NE->isArray() ? AF_CXXNewArray : AF_CXXNew));
processNewAllocation(
Call.getOriginExpr(), C, Call.getObjectUnderConstruction(),
(Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
}
}

Expand Down
31 changes: 17 additions & 14 deletions clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
const ObjCMethodCall &msg,
ExprEngine &Eng,
bool WasInlined) {
auto &checkers = getObjCMessageCheckers(visitKind);
const auto &checkers = getObjCMessageCheckers(visitKind);
CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
Expand Down Expand Up @@ -507,35 +507,38 @@ namespace {
using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;

const CheckersTy &Checkers;
const CXXNewExpr *NE;
SVal Target;
const CXXAllocatorCall &Call;
bool WasInlined;
ExprEngine &Eng;

CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE,
SVal Target, bool WasInlined, ExprEngine &Eng)
: Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined),
Eng(Eng) {}
CheckNewAllocatorContext(const CheckersTy &Checkers,
const CXXAllocatorCall &Call, bool WasInlined,
ExprEngine &Eng)
: Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}

CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }

void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext());
ProgramPoint L =
PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext());
CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
checkFn(NE, Target, C);
checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
C);
}
};

} // namespace

void CheckerManager::runCheckersForNewAllocator(
const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred,
ExprEngine &Eng, bool WasInlined) {
void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call,
ExplodedNodeSet &Dst,
ExplodedNode *Pred,
ExprEngine &Eng,
bool WasInlined) {
ExplodedNodeSet Src;
Src.insert(Pred);
CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng);
CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
expandGraphWithCheckers(C, Dst, Src);
}

Expand Down Expand Up @@ -651,7 +654,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const CallEvent &Call,
ExprEngine &Eng) {
for (const auto Pred : Src) {
for (auto *const Pred : Src) {
bool anyEvaluated = false;

ExplodedNodeSet checkDst;
Expand Down
17 changes: 8 additions & 9 deletions clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,10 @@ void ExprEngine::handleConstructor(const Expr *E,
// paths when no-return temporary destructors are used for assertions.
const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
if (TargetRegion && isa<CXXTempObjectRegion>(TargetRegion) &&
if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) &&
cast<CXXConstructorDecl>(Call->getDecl())
->getParent()->isAnyDestructorNoReturn()) {
->getParent()
->isAnyDestructorNoReturn()) {

// If we've inlined the constructor, then DstEvaluated would be empty.
// In this case we still want a sink, which could be implemented
Expand All @@ -603,7 +604,7 @@ void ExprEngine::handleConstructor(const Expr *E,
}

ExplodedNodeSet DstPostArgumentCleanup;
for (auto I : DstEvaluated)
for (ExplodedNode *I : DstEvaluated)
finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);

// If there were other constructors called for object-type arguments
Expand Down Expand Up @@ -712,7 +713,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,

ExplodedNodeSet DstPostCall;
StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
for (auto I : DstPreCall) {
for (ExplodedNode *I : DstPreCall) {
// FIXME: Provide evalCall for checkers?
defaultEvalCall(CallBldr, I, *Call);
}
Expand All @@ -722,7 +723,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
// CXXNewExpr gets processed.
ExplodedNodeSet DstPostValue;
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
// 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
Expand Down Expand Up @@ -756,10 +757,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
ExplodedNodeSet DstPostPostCallCallback;
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
DstPostValue, *Call, *this);
for (auto I : DstPostPostCallCallback) {
getCheckerManager().runCheckersForNewAllocator(
CNE, *getObjectUnderConstruction(I->getState(), CNE, LCtx), Dst, I,
*this);
for (ExplodedNode *I : DstPostPostCallCallback) {
getCheckerManager().runCheckersForNewAllocator(*Call, Dst, I, *this);
}
}

Expand Down
16 changes: 7 additions & 9 deletions clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SaveAndRestore.h"

Expand Down Expand Up @@ -325,17 +326,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);

ExplodedNodeSet DstPostCall;
if (const CXXNewExpr *CNE = dyn_cast_or_null<CXXNewExpr>(CE)) {
if (llvm::isa_and_nonnull<CXXNewExpr>(CE)) {
ExplodedNodeSet DstPostPostCallCallback;
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
CEENode, *UpdatedCall, *this,
/*wasInlined=*/true);
for (auto I : DstPostPostCallCallback) {
for (ExplodedNode *I : DstPostPostCallCallback) {
getCheckerManager().runCheckersForNewAllocator(
CNE,
*getObjectUnderConstruction(I->getState(), CNE,
calleeCtx->getParent()),
DstPostCall, I, *this,
cast<CXXAllocatorCall>(*UpdatedCall), DstPostCall, I, *this,
/*wasInlined=*/true);
}
} else {
Expand Down Expand Up @@ -591,7 +589,7 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
// If there were other constructors called for object-type arguments
// of this call, clean them up.
ExplodedNodeSet dstArgumentCleanup;
for (auto I : dstCallEvaluated)
for (ExplodedNode *I : dstCallEvaluated)
finishArgumentConstruction(dstArgumentCleanup, I, Call);

ExplodedNodeSet dstPostCall;
Expand All @@ -605,7 +603,7 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,

// Run pointerEscape callback with the newly conjured symbols.
SmallVector<std::pair<SVal, SVal>, 8> Escaped;
for (auto I : dstPostCall) {
for (ExplodedNode *I : dstPostCall) {
NodeBuilder B(I, Dst, *currBldrCtx);
ProgramStateRef State = I->getState();
Escaped.clear();
Expand Down Expand Up @@ -743,7 +741,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
const ConstructionContext *CC = CCE ? CCE->getConstructionContext()
: nullptr;

if (CC && isa<NewAllocatedObjectConstructionContext>(CC) &&
if (llvm::isa_and_nonnull<NewAllocatedObjectConstructionContext>(CC) &&
!Opts.MayInlineCXXAllocator)
return CIP_DisallowedOnce;

Expand Down

0 comments on commit f2be30d

Please sign in to comment.