Skip to content

Commit f2be30d

Browse files
committed
[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
1 parent 21d2884 commit f2be30d

File tree

8 files changed

+54
-47
lines changed

8 files changed

+54
-47
lines changed

clang/include/clang/StaticAnalyzer/Core/Checker.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,9 @@ class BranchCondition {
285285

286286
class NewAllocator {
287287
template <typename CHECKER>
288-
static void _checkNewAllocator(void *checker, const CXXNewExpr *NE,
289-
SVal Target, CheckerContext &C) {
290-
((const CHECKER *)checker)->checkNewAllocator(NE, Target, C);
288+
static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call,
289+
CheckerContext &C) {
290+
((const CHECKER *)checker)->checkNewAllocator(Call, C);
291291
}
292292

293293
public:

clang/include/clang/StaticAnalyzer/Core/CheckerManager.h

+5-6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class TranslationUnitDecl;
3737
namespace ento {
3838

3939
class AnalysisManager;
40+
class CXXAllocatorCall;
4041
class BugReporter;
4142
class CallEvent;
4243
class CheckerBase;
@@ -361,11 +362,9 @@ class CheckerManager {
361362
ExprEngine &Eng);
362363

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

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

508507
using CheckNewAllocatorFunc =
509-
CheckerFn<void (const CXXNewExpr *, SVal, CheckerContext &)>;
508+
CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>;
510509

511510
using CheckDeadSymbolsFunc =
512511
CheckerFn<void (SymbolReaper &, CheckerContext &)>;

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/ADT/STLExtras.h"
4040
#include "llvm/ADT/SmallVector.h"
4141
#include "llvm/ADT/StringRef.h"
42+
#include "llvm/ADT/iterator_range.h"
4243
#include "llvm/Support/Allocator.h"
4344
#include "llvm/Support/Casting.h"
4445
#include "llvm/Support/ErrorHandling.h"
@@ -1010,6 +1011,12 @@ class CXXAllocatorCall : public AnyFunctionCall {
10101011
return getOriginExpr()->getOperatorNew();
10111012
}
10121013

1014+
SVal getObjectUnderConstruction() const {
1015+
return ExprEngine::getObjectUnderConstruction(getState(), getOriginExpr(),
1016+
getLocationContext())
1017+
.getValue();
1018+
}
1019+
10131020
/// Number of non-placement arguments to the call. It is equal to 2 for
10141021
/// C++17 aligned operator new() calls that have alignment implicitly
10151022
/// passed as the second argument, and to 1 for other operator new() calls.

clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class AnalysisOrderChecker
165165
llvm::errs() << "EndAnalysis\n";
166166
}
167167

168-
void checkNewAllocator(const CXXNewExpr *CNE, SVal Target,
168+
void checkNewAllocator(const CXXAllocatorCall &Call,
169169
CheckerContext &C) const {
170170
if (isCallbackEnabled(C, "NewAllocator"))
171171
llvm::errs() << "NewAllocator\n";

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ class MallocChecker
315315
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
316316
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
317317
void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
318-
void checkNewAllocator(const CXXNewExpr *NE, SVal Target,
319-
CheckerContext &C) const;
318+
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
319+
void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
320320
void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
321321
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
322322
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
@@ -1357,11 +1357,12 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
13571357
}
13581358
}
13591359

1360-
void MallocChecker::checkNewAllocator(const CXXNewExpr *NE, SVal Target,
1360+
void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
13611361
CheckerContext &C) const {
13621362
if (!C.wasInlined) {
1363-
processNewAllocation(NE, C, Target,
1364-
(NE->isArray() ? AF_CXXNewArray : AF_CXXNew));
1363+
processNewAllocation(
1364+
Call.getOriginExpr(), C, Call.getObjectUnderConstruction(),
1365+
(Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
13651366
}
13661367
}
13671368

clang/lib/StaticAnalyzer/Core/CheckerManager.cpp

+17-14
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
243243
const ObjCMethodCall &msg,
244244
ExprEngine &Eng,
245245
bool WasInlined) {
246-
auto &checkers = getObjCMessageCheckers(visitKind);
246+
const auto &checkers = getObjCMessageCheckers(visitKind);
247247
CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
248248
expandGraphWithCheckers(C, Dst, Src);
249249
}
@@ -507,35 +507,38 @@ namespace {
507507
using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
508508

509509
const CheckersTy &Checkers;
510-
const CXXNewExpr *NE;
511-
SVal Target;
510+
const CXXAllocatorCall &Call;
512511
bool WasInlined;
513512
ExprEngine &Eng;
514513

515-
CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE,
516-
SVal Target, bool WasInlined, ExprEngine &Eng)
517-
: Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined),
518-
Eng(Eng) {}
514+
CheckNewAllocatorContext(const CheckersTy &Checkers,
515+
const CXXAllocatorCall &Call, bool WasInlined,
516+
ExprEngine &Eng)
517+
: Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}
519518

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

523522
void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
524523
NodeBuilder &Bldr, ExplodedNode *Pred) {
525-
ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext());
524+
ProgramPoint L =
525+
PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext());
526526
CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
527-
checkFn(NE, Target, C);
527+
checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
528+
C);
528529
}
529530
};
530531

531532
} // namespace
532533

533-
void CheckerManager::runCheckersForNewAllocator(
534-
const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred,
535-
ExprEngine &Eng, bool WasInlined) {
534+
void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call,
535+
ExplodedNodeSet &Dst,
536+
ExplodedNode *Pred,
537+
ExprEngine &Eng,
538+
bool WasInlined) {
536539
ExplodedNodeSet Src;
537540
Src.insert(Pred);
538-
CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng);
541+
CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
539542
expandGraphWithCheckers(C, Dst, Src);
540543
}
541544

@@ -651,7 +654,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
651654
const ExplodedNodeSet &Src,
652655
const CallEvent &Call,
653656
ExprEngine &Eng) {
654-
for (const auto Pred : Src) {
657+
for (auto *const Pred : Src) {
655658
bool anyEvaluated = false;
656659

657660
ExplodedNodeSet checkDst;

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

+8-9
Original file line numberDiff line numberDiff line change
@@ -577,9 +577,10 @@ void ExprEngine::handleConstructor(const Expr *E,
577577
// paths when no-return temporary destructors are used for assertions.
578578
const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
579579
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
580-
if (TargetRegion && isa<CXXTempObjectRegion>(TargetRegion) &&
580+
if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) &&
581581
cast<CXXConstructorDecl>(Call->getDecl())
582-
->getParent()->isAnyDestructorNoReturn()) {
582+
->getParent()
583+
->isAnyDestructorNoReturn()) {
583584

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

605606
ExplodedNodeSet DstPostArgumentCleanup;
606-
for (auto I : DstEvaluated)
607+
for (ExplodedNode *I : DstEvaluated)
607608
finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
608609

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

713714
ExplodedNodeSet DstPostCall;
714715
StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
715-
for (auto I : DstPreCall) {
716+
for (ExplodedNode *I : DstPreCall) {
716717
// FIXME: Provide evalCall for checkers?
717718
defaultEvalCall(CallBldr, I, *Call);
718719
}
@@ -722,7 +723,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
722723
// CXXNewExpr gets processed.
723724
ExplodedNodeSet DstPostValue;
724725
StmtNodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx);
725-
for (auto I : DstPostCall) {
726+
for (ExplodedNode *I : DstPostCall) {
726727
// FIXME: Because CNE serves as the "call site" for the allocator (due to
727728
// lack of a better expression in the AST), the conjured return value symbol
728729
// is going to be of the same type (C++ object pointer type). Technically
@@ -756,10 +757,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
756757
ExplodedNodeSet DstPostPostCallCallback;
757758
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
758759
DstPostValue, *Call, *this);
759-
for (auto I : DstPostPostCallCallback) {
760-
getCheckerManager().runCheckersForNewAllocator(
761-
CNE, *getObjectUnderConstruction(I->getState(), CNE, LCtx), Dst, I,
762-
*this);
760+
for (ExplodedNode *I : DstPostPostCallCallback) {
761+
getCheckerManager().runCheckersForNewAllocator(*Call, Dst, I, *this);
763762
}
764763
}
765764

clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

+7-9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
2222
#include "llvm/ADT/SmallSet.h"
2323
#include "llvm/ADT/Statistic.h"
24+
#include "llvm/Support/Casting.h"
2425
#include "llvm/Support/Compiler.h"
2526
#include "llvm/Support/SaveAndRestore.h"
2627

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

327328
ExplodedNodeSet DstPostCall;
328-
if (const CXXNewExpr *CNE = dyn_cast_or_null<CXXNewExpr>(CE)) {
329+
if (llvm::isa_and_nonnull<CXXNewExpr>(CE)) {
329330
ExplodedNodeSet DstPostPostCallCallback;
330331
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
331332
CEENode, *UpdatedCall, *this,
332333
/*wasInlined=*/true);
333-
for (auto I : DstPostPostCallCallback) {
334+
for (ExplodedNode *I : DstPostPostCallCallback) {
334335
getCheckerManager().runCheckersForNewAllocator(
335-
CNE,
336-
*getObjectUnderConstruction(I->getState(), CNE,
337-
calleeCtx->getParent()),
338-
DstPostCall, I, *this,
336+
cast<CXXAllocatorCall>(*UpdatedCall), DstPostCall, I, *this,
339337
/*wasInlined=*/true);
340338
}
341339
} else {
@@ -591,7 +589,7 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
591589
// If there were other constructors called for object-type arguments
592590
// of this call, clean them up.
593591
ExplodedNodeSet dstArgumentCleanup;
594-
for (auto I : dstCallEvaluated)
592+
for (ExplodedNode *I : dstCallEvaluated)
595593
finishArgumentConstruction(dstArgumentCleanup, I, Call);
596594

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

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

746-
if (CC && isa<NewAllocatedObjectConstructionContext>(CC) &&
744+
if (llvm::isa_and_nonnull<NewAllocatedObjectConstructionContext>(CC) &&
747745
!Opts.MayInlineCXXAllocator)
748746
return CIP_DisallowedOnce;
749747

0 commit comments

Comments
 (0)