Skip to content

Commit 4655163

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 e08dd79 commit 4655163

File tree

1 file changed

+53
-17
lines changed

1 file changed

+53
-17
lines changed

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

+53-17
Original file line numberDiff line numberDiff line change
@@ -1702,15 +1702,18 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
17021702
if (!State)
17031703
return nullptr;
17041704

1705-
if (Att->getModule()->getName() != "malloc")
1706-
return nullptr;
1705+
// Preseve previous behavior when "malloc" class means AF_Malloc
1706+
auto attrClassName = Att->getModule()->getName();
1707+
auto AF = attrClassName == "malloc"
1708+
? AF_Malloc
1709+
: AllocationFamily(AF_Custom, attrClassName);
17071710

17081711
if (!Att->args().empty()) {
17091712
return MallocMemAux(C, Call,
17101713
Call.getArgExpr(Att->args_begin()->getASTIndex()),
1711-
UndefinedVal(), State, AF_Malloc);
1714+
UndefinedVal(), State, AF);
17121715
}
1713-
return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State, AF_Malloc);
1716+
return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State, AF);
17141717
}
17151718

17161719
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
@@ -1862,16 +1865,18 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
18621865
if (!State)
18631866
return nullptr;
18641867

1865-
if (Att->getModule()->getName() != "malloc")
1866-
return nullptr;
1868+
// Preseve previous behavior when "malloc" class means AF_Malloc
1869+
auto attrClassName = Att->getModule()->getName();
1870+
auto AF = attrClassName == "malloc"
1871+
? AF_Malloc
1872+
: AllocationFamily(AF_Custom, attrClassName);
18671873

18681874
bool IsKnownToBeAllocated = false;
18691875

18701876
for (const auto &Arg : Att->args()) {
1871-
ProgramStateRef StateI =
1872-
FreeMemAux(C, Call, State, Arg.getASTIndex(),
1873-
Att->getOwnKind() == OwnershipAttr::Holds,
1874-
IsKnownToBeAllocated, AF_Malloc);
1877+
ProgramStateRef StateI = FreeMemAux(
1878+
C, Call, State, Arg.getASTIndex(),
1879+
Att->getOwnKind() == OwnershipAttr::Holds, IsKnownToBeAllocated, AF);
18751880
if (StateI)
18761881
State = StateI;
18771882
}
@@ -1909,6 +1914,33 @@ static bool didPreviousFreeFail(ProgramStateRef State,
19091914
return false;
19101915
}
19111916

1917+
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C,
1918+
const Expr *E) {
1919+
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1920+
const FunctionDecl *FD = CE->getDirectCallee();
1921+
if (!FD)
1922+
return;
1923+
1924+
if (FD->hasAttrs()) {
1925+
bool attrPrinted = false;
1926+
1927+
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
1928+
OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1929+
1930+
if (OwnKind == OwnershipAttr::Takes) {
1931+
if (attrPrinted)
1932+
os << ", ";
1933+
else
1934+
os << ", which takes ownership of ";
1935+
1936+
os << '\'' << I->getModule()->getName() << "'";
1937+
attrPrinted = true;
1938+
}
1939+
}
1940+
}
1941+
}
1942+
}
1943+
19121944
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {
19131945
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
19141946
// FIXME: This doesn't handle indirect calls.
@@ -1966,11 +1998,12 @@ static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
19661998
case AF_InnerBuffer:
19671999
os << "container-specific allocator";
19682000
return;
2001+
case AF_Custom:
2002+
os << Family.name().value();
2003+
return;
19692004
case AF_Alloca:
19702005
case AF_None:
19712006
llvm_unreachable("not a deallocation expression");
1972-
case AF_Custom:
1973-
llvm_unreachable("not a deallocation expression");
19742007
}
19752008
}
19762009

@@ -1991,11 +2024,12 @@ static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
19912024
case AF_InnerBuffer:
19922025
os << "container-specific deallocator";
19932026
return;
2027+
case AF_Custom:
2028+
os << "function that takes ownership of '" << Family.name().value() << "\'";
2029+
return;
19942030
case AF_Alloca:
19952031
case AF_None:
19962032
llvm_unreachable("suspicious argument");
1997-
case AF_Custom:
1998-
llvm_unreachable("suspicious argument");
19992033
}
20002034
}
20012035

@@ -2180,6 +2214,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
21802214
switch (Family.kind()) {
21812215
case AF_Malloc:
21822216
case AF_Alloca:
2217+
case AF_Custom:
21832218
case AF_IfNameIndex: {
21842219
if (ChecksEnabled[CK_MallocChecker])
21852220
return CK_MallocChecker;
@@ -2202,7 +2237,6 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
22022237
return CK_InnerPointerChecker;
22032238
return std::nullopt;
22042239
}
2205-
case AF_Custom:
22062240
case AF_None: {
22072241
llvm_unreachable("no family");
22082242
}
@@ -2432,6 +2466,8 @@ void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
24322466

24332467
if (printMemFnName(DeallocOs, C, DeallocExpr))
24342468
os << ", not " << DeallocOs.str();
2469+
2470+
printOwnershipTakesList(os, C, DeallocExpr);
24352471
}
24362472

24372473
auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
@@ -3545,6 +3581,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
35453581
switch (Family.kind()) {
35463582
case AF_Alloca:
35473583
case AF_Malloc:
3584+
case AF_Custom:
35483585
case AF_CXXNew:
35493586
case AF_CXXNewArray:
35503587
case AF_IfNameIndex:
@@ -3585,8 +3622,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
35853622
}
35863623
Msg = OS.str();
35873624
break;
3588-
}
3589-
case AF_Custom:
3625+
}
35903626
case AF_None:
35913627
llvm_unreachable("Unhandled allocation family!");
35923628
}

0 commit comments

Comments
 (0)