Skip to content

Commit 44df42e

Browse files
committed
csa/MismatchedDeallocator: handle custom allocation clasess
Patch introduces support for custom allocation classes in MismatchedDeallocator. Patch preserves previous behavior, in which 'malloc' class was handled as AF_Malloc type.
1 parent bea0ff4 commit 44df42e

File tree

1 file changed

+52
-12
lines changed

1 file changed

+52
-12
lines changed

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ struct AllocationFamily {
122122
std::optional<StringRef> name = std::nullopt)
123123
: Kind(kind), CustomName(name) {
124124
assert(kind != AF_Custom || name != std::nullopt);
125+
126+
// Preseve previous behavior when "malloc" class means AF_Malloc
127+
if (Kind == AF_Malloc && CustomName) {
128+
if (CustomName.value() == "malloc")
129+
CustomName = std::nullopt;
130+
else
131+
Kind = AF_Custom;
132+
}
125133
}
126134

127135
bool operator==(const AllocationFamily &Other) const {
@@ -1706,16 +1714,15 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
17061714
if (!State)
17071715
return nullptr;
17081716

1709-
if (Att->getModule()->getName() != "malloc")
1710-
return nullptr;
1717+
auto attrClassName = Att->getModule()->getName();
1718+
auto Family = AllocationFamily(AF_Malloc, attrClassName);
17111719

17121720
if (!Att->args().empty()) {
17131721
return MallocMemAux(C, Call,
17141722
Call.getArgExpr(Att->args_begin()->getASTIndex()),
1715-
UndefinedVal(), State, AllocationFamily(AF_Malloc));
1723+
UndefinedVal(), State, Family);
17161724
}
1717-
return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State,
1718-
AllocationFamily(AF_Malloc));
1725+
return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State, Family);
17191726
}
17201727

17211728
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
@@ -1867,14 +1874,16 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
18671874
if (!State)
18681875
return nullptr;
18691876

1870-
if (Att->getModule()->getName() != "malloc")
1871-
return nullptr;
1877+
auto attrClassName = Att->getModule()->getName();
1878+
auto Family = AllocationFamily(AF_Malloc, attrClassName);
1879+
1880+
bool IsKnownToBeAllocated = false;
18721881

18731882
for (const auto &Arg : Att->args()) {
18741883
ProgramStateRef StateI =
18751884
FreeMemAux(C, Call, State, Arg.getASTIndex(),
18761885
Att->getOwnKind() == OwnershipAttr::Holds,
1877-
IsKnownToBeAllocated, AllocationFamily(AF_Malloc));
1886+
IsKnownToBeAllocated, Family);
18781887
if (StateI)
18791888
State = StateI;
18801889
}
@@ -1912,6 +1921,30 @@ static bool didPreviousFreeFail(ProgramStateRef State,
19121921
return false;
19131922
}
19141923

1924+
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C,
1925+
const Expr *E) {
1926+
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1927+
const FunctionDecl *FD = CE->getDirectCallee();
1928+
if (!FD)
1929+
return;
1930+
1931+
if (!FD->hasAttrs())
1932+
return;
1933+
1934+
// Only one ownership_takes attribute is allowed
1935+
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
1936+
OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1937+
1938+
if (OwnKind != OwnershipAttr::Takes)
1939+
continue;
1940+
1941+
os << ", which takes ownership of "
1942+
<< '\'' << I->getModule()->getName() << '\'';
1943+
break;
1944+
}
1945+
}
1946+
}
1947+
19151948
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {
19161949
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
19171950
// FIXME: This doesn't handle indirect calls.
@@ -1969,8 +2002,10 @@ static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
19692002
case AF_InnerBuffer:
19702003
os << "container-specific allocator";
19712004
return;
1972-
case AF_Alloca:
19732005
case AF_Custom:
2006+
os << Family.CustomName.value();
2007+
return;
2008+
case AF_Alloca:
19742009
case AF_None:
19752010
assert(false && "not a deallocation expression");
19762011
}
@@ -1993,8 +2028,11 @@ static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
19932028
case AF_InnerBuffer:
19942029
os << "container-specific deallocator";
19952030
return;
1996-
case AF_Alloca:
19972031
case AF_Custom:
2032+
os << "function that takes ownership of '" << Family.CustomName.value()
2033+
<< "\'";
2034+
return;
2035+
case AF_Alloca:
19982036
case AF_None:
19992037
assert(false && "not a deallocation expression");
20002038
}
@@ -2181,6 +2219,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
21812219
switch (Family.Kind) {
21822220
case AF_Malloc:
21832221
case AF_Alloca:
2222+
case AF_Custom:
21842223
case AF_IfNameIndex: {
21852224
if (ChecksEnabled[CK_MallocChecker])
21862225
return CK_MallocChecker;
@@ -2203,7 +2242,6 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
22032242
return CK_InnerPointerChecker;
22042243
return std::nullopt;
22052244
}
2206-
case AF_Custom:
22072245
case AF_None: {
22082246
assert(false && "no family");
22092247
}
@@ -2433,6 +2471,8 @@ void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
24332471

24342472
if (printMemFnName(DeallocOs, C, DeallocExpr))
24352473
os << ", not " << DeallocOs.str();
2474+
2475+
printOwnershipTakesList(os, C, DeallocExpr);
24362476
}
24372477

24382478
auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
@@ -3548,6 +3588,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
35483588
switch (Family.Kind) {
35493589
case AF_Alloca:
35503590
case AF_Malloc:
3591+
case AF_Custom:
35513592
case AF_CXXNew:
35523593
case AF_CXXNewArray:
35533594
case AF_IfNameIndex:
@@ -3589,7 +3630,6 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
35893630
Msg = OS.str();
35903631
break;
35913632
}
3592-
case AF_Custom:
35933633
case AF_None:
35943634
assert(false && "Unhandled allocation family!");
35953635
}

0 commit comments

Comments
 (0)