Skip to content

Commit 44fe99c

Browse files
committed
[analyzer] Fix a false memory leak report involving placement new
Placement new does not allocate memory, so it should not be reported as a memory leak. A recent MallocChecker refactor changed inlining of placement-new calls with manual evaluation by MallocChecker. 339282d This change avoids marking the value returned by placement new as allocated and hence avoids the false leak reports. --- CPP-6375
1 parent 9e62298 commit 44fe99c

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,19 @@ void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,
13711371
C.addTransition(State);
13721372
}
13731373

1374+
bool isVoidStar(QualType T) {
1375+
return !T.isNull() && T->isPointerType() && T->getPointeeType()->isVoidType();
1376+
}
1377+
1378+
const Expr* getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD) {
1379+
if (CE->getNumArgs() == 1)
1380+
return nullptr;
1381+
// Second argument of placement new must be void*
1382+
if (!isVoidStar(FD->getParamDecl(1)->getType()))
1383+
return nullptr;
1384+
return CE->getArg(1);
1385+
}
1386+
13741387
void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
13751388
const CallEvent &Call,
13761389
CheckerContext &C) const {
@@ -1386,6 +1399,14 @@ void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
13861399
// processed by the checkPostStmt callbacks for CXXNewExpr and
13871400
// CXXDeleteExpr.
13881401
const FunctionDecl *FD = C.getCalleeDecl(CE);
1402+
if (const auto *BufArg = getPlacementNewBufferArg(CE, FD)) {
1403+
// Placement new does not allocate memory
1404+
auto RetVal = State->getSVal(BufArg, Call.getLocationContext());
1405+
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
1406+
C.addTransition(State);
1407+
return;
1408+
}
1409+
13891410
switch (FD->getOverloadedOperator()) {
13901411
case OO_New:
13911412
State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,

clang/test/Analysis/NewDelete-checker-test.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
2727
//
2828
// RUN: %clang_analyze_cc1 -std=c++17 -fblocks -verify %s \
29-
// RUN: -verify=expected,leak \
29+
// RUN: -verify=expected,leak,inspection \
3030
// RUN: -analyzer-checker=core \
31-
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
31+
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \
32+
// RUN: -analyzer-checker=debug.ExprInspection
3233

3334
#include "Inputs/system-header-simulator-cxx.h"
3435

@@ -63,6 +64,42 @@ void testGlobalNoThrowPlacementExprNewBeforeOverload() {
6364
int *p = new(std::nothrow) int;
6465
} // leak-warning{{Potential leak of memory pointed to by 'p'}}
6566

67+
//----- Standard pointer placement operators
68+
void testGlobalPointerPlacementNew() {
69+
int i;
70+
void *p1 = operator new(0, &i); // no warn
71+
72+
void *p2 = operator new[](0, &i); // no warn
73+
74+
int *p3 = new(&i) int; // no warn
75+
76+
int *p4 = new(&i) int[0]; // no warn
77+
}
78+
79+
template<typename T>
80+
void clang_analyzer_dump(T x);
81+
82+
void testPlacementNewBufValue() {
83+
int i = 10;
84+
int *p = new(&i) int;
85+
clang_analyzer_dump(p); // inspection-warning{{&i}}
86+
clang_analyzer_dump(*p); // inspection-warning{{10}}
87+
}
88+
89+
void testPlacementNewBufValueExplicitOp() {
90+
int i = 10;
91+
int *p = (int*)operator new(sizeof(int), &i);
92+
clang_analyzer_dump(p); // inspection-warning{{&i}}
93+
clang_analyzer_dump(*p); // inspection-warning{{10}}
94+
}
95+
96+
void testPlacementArrNewBufValueExplicitArrOp() {
97+
int i = 10;
98+
int *p = (int*)operator new[](sizeof(int), &i);
99+
clang_analyzer_dump(p); // inspection-warning{{&i}}
100+
clang_analyzer_dump(*p); // inspection-warning{{10}}
101+
}
102+
66103
//----- Other cases
67104
void testNewMemoryIsInHeap() {
68105
int *p = new int;

0 commit comments

Comments
 (0)