This revision was automatically updated to reflect the committed changes.
Closed by commit rG9fd7ce7f4449: [analyzer][MallocChecker][NFC] Communicate the
allocation family to auxiliary… (authored by Szelethus).
Herald added subscribers: martong, steakhal.
Changed prior to commit:
https://reviews.llvm.org/D68162?vs=222781&id=246390#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D68162/new/
https://reviews.llvm.org/D68162
Files:
clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -44,13 +44,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "AllocationState.h"
#include "InterCheckerAPI.h"
#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -64,7 +65,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "AllocationState.h"
+#include "llvm/Support/ErrorHandling.h"
#include <climits>
#include <utility>
@@ -72,7 +73,10 @@
using namespace ento;
//===----------------------------------------------------------------------===//
-// The types of allocation we're modeling.
+// The types of allocation we're modeling. This is used to check whether a
+// dynamically allocated object is deallocated with the correct function, like
+// not using operator delete on an object created by malloc(), or alloca regions
+// aren't ever deallocated manually.
//===----------------------------------------------------------------------===//
namespace {
@@ -92,22 +96,14 @@
} // end of anonymous namespace
-/// Determine family of a deallocation expression.
-static AllocationFamily
-getAllocationFamily(const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C,
- const Stmt *S);
-
/// Print names of allocators and deallocators.
///
/// \returns true on success.
-static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
- const Expr *E);
+static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E);
-/// Print expected name of an allocator based on the deallocator's
-/// family derived from the DeallocExpr.
-static void printExpectedAllocName(raw_ostream &os,
- const MemFunctionInfoTy &MemFunctionInfo,
- CheckerContext &C, const Expr *E);
+/// Print expected name of an allocator based on the deallocator's family
+/// derived from the DeallocExpr.
+static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family);
/// Print expected name of a deallocator based on the allocator's
/// family.
@@ -208,7 +204,7 @@
/// value; if unspecified, the value of expression \p E is used.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
ProgramStateRef State,
- AllocationFamily Family = AF_Malloc,
+ AllocationFamily Family,
Optional<SVal> RetVal = None);
//===----------------------------------------------------------------------===//
@@ -402,7 +398,7 @@
/// Process C++ operator new()'s allocation, which is the part of C++
/// new-expression that goes before the constructor.
void processNewAllocation(const CXXNewExpr *NE, CheckerContext &C,
- SVal Target) const;
+ SVal Target, AllocationFamily Family) const;
/// Perform a zero-allocation check.
///
@@ -450,7 +446,7 @@
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
- AllocationFamily Family = AF_Malloc);
+ AllocationFamily Family);
/// Models memory allocation.
///
@@ -464,7 +460,7 @@
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal Size, SVal Init,
ProgramStateRef State,
- AllocationFamily Family = AF_Malloc);
+ AllocationFamily Family);
static ProgramStateRef addExtentSize(CheckerContext &C, const CXXNewExpr *NE,
ProgramStateRef State, SVal Target);
@@ -518,6 +514,7 @@
ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State, unsigned Num, bool Hold,
bool &IsKnownToBeAllocated,
+ AllocationFamily Family,
bool ReturnsNullOnFailure = false) const;
/// Models memory deallocation.
@@ -542,6 +539,7 @@
ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
const Expr *ParentExpr, ProgramStateRef State,
bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family,
bool ReturnsNullOnFailure = false) const;
// TODO: Needs some refactoring, as all other deallocation modeling
@@ -559,6 +557,7 @@
/// \returns The ProgramState right after reallocation.
ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
bool ShouldFreeOnFail, ProgramStateRef State,
+ AllocationFamily Family,
bool SuffixWithN = false) const;
/// Evaluates the buffer size that needs to be allocated.
@@ -623,9 +622,7 @@
/// family/call/symbol.
Optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
bool IsALeakCheck = false) const;
- Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
- const Stmt *AllocDeallocStmt,
- bool IsALeakCheck = false) const;
+
Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
bool IsALeakCheck = false) const;
///@}
@@ -633,17 +630,22 @@
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
- const Expr *DeallocExpr) const;
+ const Expr *DeallocExpr, AllocationFamily Family) const;
+
void ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const;
+
void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
const Expr *DeallocExpr, const RefState *RS,
SymbolRef Sym, bool OwnershipTransferred) const;
+
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
- const Expr *DeallocExpr,
+ const Expr *DeallocExpr, AllocationFamily Family,
const Expr *AllocExpr = nullptr) const;
+
void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const;
+
void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
SymbolRef Sym, SymbolRef PrevSym) const;
@@ -653,7 +655,8 @@
SymbolRef Sym) const;
void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
- SourceRange Range, const Expr *FreeExpr) const;
+ SourceRange Range, const Expr *FreeExpr,
+ AllocationFamily Family) const;
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
@@ -1036,7 +1039,7 @@
// If M_ZERO is set, treat this like calloc (initialized).
if (TrueState && !FalseState) {
SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
- return MallocMemAux(C, CE, CE->getArg(0), ZeroVal, TrueState);
+ return MallocMemAux(C, CE, CE->getArg(0), ZeroVal, TrueState, AF_Malloc);
}
return None;
@@ -1075,11 +1078,13 @@
default:
return;
case 1:
- State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 0, State);
break;
case 2:
- State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_Malloc);
break;
case 3:
llvm::Optional<ProgramStateRef> MaybeState =
@@ -1087,7 +1092,8 @@
if (MaybeState.hasValue())
State = MaybeState.getValue();
else
- State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_Malloc);
break;
}
} else if (FunI == MemFunctionInfo.II_kmalloc) {
@@ -1098,19 +1104,22 @@
if (MaybeState.hasValue())
State = MaybeState.getValue();
else
- State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_Malloc);
} else if (FunI == MemFunctionInfo.II_valloc) {
if (CE->getNumArgs() < 1)
return;
- State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State =
+ MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 0, State);
} else if (FunI == MemFunctionInfo.II_realloc ||
FunI == MemFunctionInfo.II_g_realloc ||
FunI == MemFunctionInfo.II_g_try_realloc) {
- State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State);
+ State =
+ ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 1, State);
} else if (FunI == MemFunctionInfo.II_reallocf) {
- State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ true, State);
+ State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ true, State, AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 1, State);
} else if (FunI == MemFunctionInfo.II_calloc) {
State = CallocMem(C, CE, State);
@@ -1122,20 +1131,21 @@
if (suppressDeallocationsInSuspiciousContexts(CE, C))
return;
- State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+ AF_Malloc);
} else if (FunI == MemFunctionInfo.II_strdup ||
FunI == MemFunctionInfo.II_win_strdup ||
FunI == MemFunctionInfo.II_wcsdup ||
FunI == MemFunctionInfo.II_win_wcsdup) {
- State = MallocUpdateRefState(C, CE, State);
+ State = MallocUpdateRefState(C, CE, State, AF_Malloc);
} else if (FunI == MemFunctionInfo.II_strndup) {
- State = MallocUpdateRefState(C, CE, State);
+ State = MallocUpdateRefState(C, CE, State, AF_Malloc);
} else if (FunI == MemFunctionInfo.II_alloca ||
FunI == MemFunctionInfo.II_win_alloca) {
if (CE->getNumArgs() < 1)
return;
- State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
- AF_Alloca);
+ State =
+ MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Alloca);
State = ProcessZeroAllocCheck(C, CE, 0, State);
} else if (MemFunctionInfo.isStandardNewDelete(FD, C.getASTContext())) {
// Process direct calls to operator new/new[]/delete/delete[] functions
@@ -1154,8 +1164,12 @@
State = ProcessZeroAllocCheck(C, CE, 0, State);
break;
case OO_Delete:
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+ AF_CXXNew);
+ break;
case OO_Array_Delete:
- State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+ AF_CXXNewArray);
break;
default:
llvm_unreachable("not a new/delete operator");
@@ -1166,19 +1180,21 @@
State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State,
AF_IfNameIndex);
} else if (FunI == MemFunctionInfo.II_if_freenameindex) {
- State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+ AF_IfNameIndex);
} else if (FunI == MemFunctionInfo.II_g_malloc0 ||
FunI == MemFunctionInfo.II_g_try_malloc0) {
if (CE->getNumArgs() < 1)
return;
SValBuilder &svalBuilder = C.getSValBuilder();
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
- State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State);
+ State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State, AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 0, State);
} else if (FunI == MemFunctionInfo.II_g_memdup) {
if (CE->getNumArgs() < 2)
return;
- State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
+ State =
+ MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State, AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 1, State);
} else if (FunI == MemFunctionInfo.II_g_malloc_n ||
FunI == MemFunctionInfo.II_g_try_malloc_n ||
@@ -1193,14 +1209,14 @@
Init = SB.makeZeroVal(SB.getContext().CharTy);
}
SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
- State = MallocMemAux(C, CE, TotalSize, Init, State);
+ State = MallocMemAux(C, CE, TotalSize, Init, State, AF_Malloc);
State = ProcessZeroAllocCheck(C, CE, 0, State);
State = ProcessZeroAllocCheck(C, CE, 1, State);
} else if (FunI == MemFunctionInfo.II_g_realloc_n ||
FunI == MemFunctionInfo.II_g_try_realloc_n) {
if (CE->getNumArgs() < 3)
return;
- State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State,
+ State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, AF_Malloc,
/*SuffixWithN*/ true);
State = ProcessZeroAllocCheck(C, CE, 1, State);
State = ProcessZeroAllocCheck(C, CE, 2, State);
@@ -1332,8 +1348,8 @@
}
void MallocChecker::processNewAllocation(const CXXNewExpr *NE,
- CheckerContext &C,
- SVal Target) const {
+ CheckerContext &C, SVal Target,
+ AllocationFamily Family) const {
if (!MemFunctionInfo.isStandardNewDelete(NE->getOperatorNew(),
C.getASTContext()))
return;
@@ -1352,8 +1368,7 @@
// value (if any) and we don't want to loose this value. So we call
// MallocUpdateRefState() instead of MallocMemAux() which breaks the
// existing binding.
- State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
- : AF_CXXNew, Target);
+ State = MallocUpdateRefState(C, NE, State, Family, Target);
State = addExtentSize(C, NE, State, Target);
State = ProcessZeroAllocCheck(C, NE, 0, State, Target);
C.addTransition(State);
@@ -1361,14 +1376,19 @@
void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
CheckerContext &C) const {
- if (!C.getAnalysisManager().getAnalyzerOptions().MayInlineCXXAllocator)
- processNewAllocation(NE, C, C.getSVal(NE));
+ if (!C.getAnalysisManager().getAnalyzerOptions().MayInlineCXXAllocator) {
+ if (NE->isArray())
+ processNewAllocation(NE, C, C.getSVal(NE),
+ (NE->isArray() ? AF_CXXNewArray : AF_CXXNew));
+ }
}
void MallocChecker::checkNewAllocator(const CXXNewExpr *NE, SVal Target,
CheckerContext &C) const {
- if (!C.wasInlined)
- processNewAllocation(NE, C, Target);
+ if (!C.wasInlined) {
+ processNewAllocation(NE, C, Target,
+ (NE->isArray() ? AF_CXXNewArray : AF_CXXNew));
+ }
}
// Sets the extent value of the MemRegion allocated by
@@ -1431,7 +1451,8 @@
ProgramStateRef State = C.getState();
bool IsKnownToBeAllocated;
State = FreeMemAux(C, DE->getArgument(), DE, State,
- /*Hold*/ false, IsKnownToBeAllocated);
+ /*Hold*/ false, IsKnownToBeAllocated,
+ (DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
C.addTransition(State);
}
@@ -1477,7 +1498,7 @@
bool IsKnownToBeAllocatedMemory;
ProgramStateRef State =
FreeMemAux(C, Call.getArgExpr(0), Call.getOriginExpr(), C.getState(),
- /*Hold=*/true, IsKnownToBeAllocatedMemory,
+ /*Hold=*/true, IsKnownToBeAllocatedMemory, AF_Malloc,
/*RetNullOnFailure=*/true);
C.addTransition(State);
@@ -1496,9 +1517,9 @@
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
if (I != E) {
return MallocMemAux(C, CE, CE->getArg(I->getASTIndex()), UndefinedVal(),
- State);
+ State, AF_Malloc);
}
- return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State);
+ return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State, AF_Malloc);
}
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
@@ -1513,10 +1534,9 @@
}
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
- const CallExpr *CE,
- SVal Size, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family) {
+ const CallExpr *CE, SVal Size,
+ SVal Init, ProgramStateRef State,
+ AllocationFamily Family) {
if (!State)
return nullptr;
@@ -1593,9 +1613,10 @@
bool IsKnownToBeAllocated = false;
for (const auto &Arg : Att->args()) {
- ProgramStateRef StateI = FreeMemAux(
- C, CE, State, Arg.getASTIndex(),
- Att->getOwnKind() == OwnershipAttr::Holds, IsKnownToBeAllocated);
+ ProgramStateRef StateI =
+ FreeMemAux(C, CE, State, Arg.getASTIndex(),
+ Att->getOwnKind() == OwnershipAttr::Holds,
+ IsKnownToBeAllocated, AF_Malloc);
if (StateI)
State = StateI;
}
@@ -1605,6 +1626,7 @@
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State, unsigned Num,
bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family,
bool ReturnsNullOnFailure) const {
if (!State)
return nullptr;
@@ -1613,7 +1635,7 @@
return nullptr;
return FreeMemAux(C, CE->getArg(Num), CE, State, Hold, IsKnownToBeAllocated,
- ReturnsNullOnFailure);
+ Family, ReturnsNullOnFailure);
}
/// Checks if the previous call to free on the given symbol failed - if free
@@ -1631,58 +1653,7 @@
return false;
}
-static AllocationFamily
-getAllocationFamily(const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C,
- const Stmt *S) {
-
- if (!S)
- return AF_None;
-
- if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
- const FunctionDecl *FD = C.getCalleeDecl(CE);
-
- if (!FD)
- FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
-
- ASTContext &Ctx = C.getASTContext();
-
- if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc,
- MemoryOperationKind::MOK_Any))
- return AF_Malloc;
-
- if (MemFunctionInfo.isStandardNewDelete(FD, Ctx)) {
- OverloadedOperatorKind Kind = FD->getOverloadedOperator();
- if (Kind == OO_New || Kind == OO_Delete)
- return AF_CXXNew;
- else if (Kind == OO_Array_New || Kind == OO_Array_Delete)
- return AF_CXXNewArray;
- }
-
- if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex,
- MemoryOperationKind::MOK_Any))
- return AF_IfNameIndex;
-
- if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Alloca,
- MemoryOperationKind::MOK_Any))
- return AF_Alloca;
-
- return AF_None;
- }
-
- if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(S))
- return NE->isArray() ? AF_CXXNewArray : AF_CXXNew;
-
- if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(S))
- return DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew;
-
- if (isa<ObjCMessageExpr>(S))
- return AF_Malloc;
-
- return AF_None;
-}
-
-static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
- const Expr *E) {
+static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
// FIXME: This doesn't handle indirect calls.
const FunctionDecl *FD = CE->getDirectCallee();
@@ -1721,10 +1692,7 @@
return false;
}
-static void printExpectedAllocName(raw_ostream &os,
- const MemFunctionInfoTy &MemFunctionInfo,
- CheckerContext &C, const Expr *E) {
- AllocationFamily Family = getAllocationFamily(MemFunctionInfo, C, E);
+static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
switch(Family) {
case AF_Malloc: os << "malloc()"; return;
@@ -1749,12 +1717,10 @@
}
}
-ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
- const Expr *ArgExpr,
- const Expr *ParentExpr,
- ProgramStateRef State, bool Hold,
- bool &IsKnownToBeAllocated,
- bool ReturnsNullOnFailure) const {
+ProgramStateRef MallocChecker::FreeMemAux(
+ CheckerContext &C, const Expr *ArgExpr, const Expr *ParentExpr,
+ ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family, bool ReturnsNullOnFailure) const {
if (!State)
return nullptr;
@@ -1784,7 +1750,7 @@
// Nonlocs can't be freed, of course.
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
if (!R) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family);
return nullptr;
}
@@ -1792,7 +1758,7 @@
// Blocks might show up as heap data, but should not be free()d
if (isa<BlockDataRegion>(R)) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family);
return nullptr;
}
@@ -1812,7 +1778,7 @@
if (isa<AllocaRegion>(R))
ReportFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
else
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family);
return nullptr;
}
@@ -1851,9 +1817,7 @@
RsBase->isEscaped()) {
// Check if an expected deallocation function matches the real one.
- bool DeallocMatchesAlloc =
- RsBase->getAllocationFamily() ==
- getAllocationFamily(MemFunctionInfo, C, ParentExpr);
+ bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
if (!DeallocMatchesAlloc) {
ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
ParentExpr, RsBase, SymBase, Hold);
@@ -1868,14 +1832,15 @@
Offset.getOffset() != 0) {
const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
- AllocExpr);
+ Family, AllocExpr);
return nullptr;
}
}
}
if (SymBase->getType()->isFunctionPointerType()) {
- ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+ ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
+ Family);
return nullptr;
}
@@ -1893,9 +1858,12 @@
}
}
- AllocationFamily Family =
- RsBase ? RsBase->getAllocationFamily()
- : getAllocationFamily(MemFunctionInfo, C, ParentExpr);
+ // If we don't know anything about this symbol, a free on it may be totally
+ // valid. If this is the case, lets assume that the allocation family of the
+ // freeing function is the same as the symbols allocation family, and go with
+ // that.
+ assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
+
// Normal free.
if (Hold)
return State->set<RegionState>(SymBase,
@@ -1942,14 +1910,6 @@
}
Optional<MallocChecker::CheckKind>
-MallocChecker::getCheckIfTracked(CheckerContext &C,
- const Stmt *AllocDeallocStmt,
- bool IsALeakCheck) const {
- return getCheckIfTracked(
- getAllocationFamily(MemFunctionInfo, C, AllocDeallocStmt), IsALeakCheck);
-}
-
-Optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
bool IsALeakCheck) const {
if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
@@ -2048,15 +2008,14 @@
}
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
- SourceRange Range,
- const Expr *DeallocExpr) const {
+ SourceRange Range, const Expr *DeallocExpr,
+ AllocationFamily Family) const {
if (!ChecksEnabled[CK_MallocChecker] &&
!ChecksEnabled[CK_NewDeleteChecker])
return;
- Optional<MallocChecker::CheckKind> CheckKind =
- getCheckIfTracked(C, DeallocExpr);
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind.hasValue())
return;
@@ -2073,7 +2032,7 @@
MR = ER->getSuperRegion();
os << "Argument to ";
- if (!printAllocDeallocName(os, C, DeallocExpr))
+ if (!printMemFnName(os, C, DeallocExpr))
os << "deallocator";
os << " is ";
@@ -2084,7 +2043,7 @@
else
os << "not memory allocated by ";
- printExpectedAllocName(os, MemFunctionInfo, C, DeallocExpr);
+ printExpectedAllocName(os, Family);
auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
os.str(), N);
@@ -2146,25 +2105,25 @@
llvm::raw_svector_ostream DeallocOs(DeallocBuf);
if (OwnershipTransferred) {
- if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
+ if (printMemFnName(DeallocOs, C, DeallocExpr))
os << DeallocOs.str() << " cannot";
else
os << "Cannot";
os << " take ownership of memory";
- if (printAllocDeallocName(AllocOs, C, AllocExpr))
+ if (printMemFnName(AllocOs, C, AllocExpr))
os << " allocated by " << AllocOs.str();
} else {
os << "Memory";
- if (printAllocDeallocName(AllocOs, C, AllocExpr))
+ if (printMemFnName(AllocOs, C, AllocExpr))
os << " allocated by " << AllocOs.str();
os << " should be deallocated by ";
printExpectedDeallocName(os, RS->getAllocationFamily());
- if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
- os << ", not " << DeallocOs.str();
+ if (printMemFnName(DeallocOs, C, DeallocExpr))
+ os << ", not " << DeallocOs.str();
}
auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
@@ -2178,15 +2137,14 @@
void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
SourceRange Range, const Expr *DeallocExpr,
+ AllocationFamily Family,
const Expr *AllocExpr) const {
-
if (!ChecksEnabled[CK_MallocChecker] &&
!ChecksEnabled[CK_NewDeleteChecker])
return;
- Optional<MallocChecker::CheckKind> CheckKind =
- getCheckIfTracked(C, AllocExpr);
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind.hasValue())
return;
@@ -2215,14 +2173,14 @@
int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
os << "Argument to ";
- if (!printAllocDeallocName(os, C, DeallocExpr))
+ if (!printMemFnName(os, C, DeallocExpr))
os << "deallocator";
os << " is offset by "
<< offsetBytes
<< " "
<< ((abs(offsetBytes) > 1) ? "bytes" : "byte")
<< " from the start of ";
- if (AllocExpr && printAllocDeallocName(AllocNameOs, C, AllocExpr))
+ if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
os << "memory allocated by " << AllocNameOs.str();
else
os << "allocated memory";
@@ -2360,11 +2318,12 @@
void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
SourceRange Range,
- const Expr *FreeExpr) const {
+ const Expr *FreeExpr,
+ AllocationFamily Family) const {
if (!ChecksEnabled[CK_MallocChecker])
return;
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, FreeExpr);
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind.hasValue())
return;
@@ -2381,7 +2340,7 @@
MR = ER->getSuperRegion();
Os << "Argument to ";
- if (!printAllocDeallocName(Os, C, FreeExpr))
+ if (!printMemFnName(Os, C, FreeExpr))
Os << "deallocator";
Os << " is a function pointer";
@@ -2394,11 +2353,10 @@
}
}
-ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
- const CallExpr *CE,
- bool ShouldFreeOnFail,
- ProgramStateRef State,
- bool SuffixWithN) const {
+ProgramStateRef
+MallocChecker::ReallocMemAux(CheckerContext &C, const CallExpr *CE,
+ bool ShouldFreeOnFail, ProgramStateRef State,
+ AllocationFamily Family, bool SuffixWithN) const {
if (!State)
return nullptr;
@@ -2445,8 +2403,8 @@
// If the ptr is NULL and the size is not 0, the call is equivalent to
// malloc(size).
if (PrtIsNull && !SizeIsZero) {
- ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize,
- UndefinedVal(), StatePtrIsNull);
+ ProgramStateRef stateMalloc =
+ MallocMemAux(C, CE, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
return stateMalloc;
}
@@ -2469,16 +2427,16 @@
// If size was equal to 0, either NULL or a pointer suitable to be passed
// to free() is returned. We just free the input pointer and do not add
// any constrains on the output pointer.
- if (ProgramStateRef stateFree =
- FreeMemAux(C, CE, StateSizeIsZero, 0, false, IsKnownToBeAllocated))
+ if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0, false,
+ IsKnownToBeAllocated, Family))
return stateFree;
// Default behavior.
if (ProgramStateRef stateFree =
- FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated)) {
+ FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated, Family)) {
- ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
- UnknownVal(), stateFree);
+ ProgramStateRef stateRealloc =
+ MallocMemAux(C, CE, TotalSize, UnknownVal(), stateFree, Family);
if (!stateRealloc)
return nullptr;
@@ -2511,7 +2469,7 @@
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
- return MallocMemAux(C, CE, TotalSize, zeroVal, State);
+ return MallocMemAux(C, CE, TotalSize, zeroVal, State, AF_Malloc);
}
MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
Index: clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
+++ clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
@@ -11,13 +11,19 @@
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_INTERCHECKERAPI_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_INTERCHECKERAPI_H
-namespace clang {
-class CheckerManager;
+// FIXME: This file goes against how a checker should be implemented either in
+// a single file, or be exposed in a header file. Let's try to get rid of it!
+
+namespace clang {
namespace ento {
+class CheckerManager;
+
/// Register the part of MallocChecker connected to InnerPointerChecker.
void registerInnerPointerCheckerAux(CheckerManager &Mgr);
-}}
+} // namespace ento
+} // namespace clang
+
#endif /* INTERCHECKERAPI_H_ */
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits