@@ -122,6 +122,14 @@ struct AllocationFamily {
122
122
std::optional<StringRef> name = std::nullopt)
123
123
: Kind(kind), CustomName(name) {
124
124
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
+ }
125
133
}
126
134
127
135
bool operator ==(const AllocationFamily &Other) const {
@@ -1706,16 +1714,15 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
1706
1714
if (!State)
1707
1715
return nullptr ;
1708
1716
1709
- if ( Att->getModule ()->getName () != " malloc " )
1710
- return nullptr ;
1717
+ auto attrClassName = Att->getModule ()->getName ();
1718
+ auto Family = AllocationFamily (AF_Malloc, attrClassName) ;
1711
1719
1712
1720
if (!Att->args ().empty ()) {
1713
1721
return MallocMemAux (C, Call,
1714
1722
Call.getArgExpr (Att->args_begin ()->getASTIndex ()),
1715
- UndefinedVal (), State, AllocationFamily (AF_Malloc) );
1723
+ UndefinedVal (), State, Family );
1716
1724
}
1717
- return MallocMemAux (C, Call, UnknownVal (), UndefinedVal (), State,
1718
- AllocationFamily (AF_Malloc));
1725
+ return MallocMemAux (C, Call, UnknownVal (), UndefinedVal (), State, Family);
1719
1726
}
1720
1727
1721
1728
ProgramStateRef MallocChecker::MallocMemAux (CheckerContext &C,
@@ -1867,14 +1874,16 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
1867
1874
if (!State)
1868
1875
return nullptr ;
1869
1876
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 ;
1872
1881
1873
1882
for (const auto &Arg : Att->args ()) {
1874
1883
ProgramStateRef StateI =
1875
1884
FreeMemAux (C, Call, State, Arg.getASTIndex (),
1876
1885
Att->getOwnKind () == OwnershipAttr::Holds,
1877
- IsKnownToBeAllocated, AllocationFamily (AF_Malloc) );
1886
+ IsKnownToBeAllocated, Family );
1878
1887
if (StateI)
1879
1888
State = StateI;
1880
1889
}
@@ -1912,6 +1921,30 @@ static bool didPreviousFreeFail(ProgramStateRef State,
1912
1921
return false ;
1913
1922
}
1914
1923
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
+
1915
1948
static bool printMemFnName (raw_ostream &os, CheckerContext &C, const Expr *E) {
1916
1949
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1917
1950
// FIXME: This doesn't handle indirect calls.
@@ -1969,8 +2002,10 @@ static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
1969
2002
case AF_InnerBuffer:
1970
2003
os << " container-specific allocator" ;
1971
2004
return ;
1972
- case AF_Alloca:
1973
2005
case AF_Custom:
2006
+ os << Family.CustomName .value ();
2007
+ return ;
2008
+ case AF_Alloca:
1974
2009
case AF_None:
1975
2010
assert (false && " not a deallocation expression" );
1976
2011
}
@@ -1993,8 +2028,11 @@ static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
1993
2028
case AF_InnerBuffer:
1994
2029
os << " container-specific deallocator" ;
1995
2030
return ;
1996
- case AF_Alloca:
1997
2031
case AF_Custom:
2032
+ os << " function that takes ownership of '" << Family.CustomName .value ()
2033
+ << " \' " ;
2034
+ return ;
2035
+ case AF_Alloca:
1998
2036
case AF_None:
1999
2037
assert (false && " not a deallocation expression" );
2000
2038
}
@@ -2181,6 +2219,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
2181
2219
switch (Family.Kind ) {
2182
2220
case AF_Malloc:
2183
2221
case AF_Alloca:
2222
+ case AF_Custom:
2184
2223
case AF_IfNameIndex: {
2185
2224
if (ChecksEnabled[CK_MallocChecker])
2186
2225
return CK_MallocChecker;
@@ -2203,7 +2242,6 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
2203
2242
return CK_InnerPointerChecker;
2204
2243
return std::nullopt;
2205
2244
}
2206
- case AF_Custom:
2207
2245
case AF_None: {
2208
2246
assert (false && " no family" );
2209
2247
}
@@ -2433,6 +2471,8 @@ void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
2433
2471
2434
2472
if (printMemFnName (DeallocOs, C, DeallocExpr))
2435
2473
os << " , not " << DeallocOs.str ();
2474
+
2475
+ printOwnershipTakesList (os, C, DeallocExpr);
2436
2476
}
2437
2477
2438
2478
auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
@@ -3548,6 +3588,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
3548
3588
switch (Family.Kind ) {
3549
3589
case AF_Alloca:
3550
3590
case AF_Malloc:
3591
+ case AF_Custom:
3551
3592
case AF_CXXNew:
3552
3593
case AF_CXXNewArray:
3553
3594
case AF_IfNameIndex:
@@ -3589,7 +3630,6 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
3589
3630
Msg = OS.str ();
3590
3631
break ;
3591
3632
}
3592
- case AF_Custom:
3593
3633
case AF_None:
3594
3634
assert (false && " Unhandled allocation family!" );
3595
3635
}
0 commit comments