r301384 - [analyzer] Teach the MallocChecker about Glib API for two arguments
Leslie Zhai via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 25 22:33:14 PDT 2017
Author: xiangzhai
Date: Wed Apr 26 00:33:14 2017
New Revision: 301384
URL: http://llvm.org/viewvc/llvm-project?rev=301384&view=rev
Log:
[analyzer] Teach the MallocChecker about Glib API for two arguments
Reviewers: zaks.anna, NoQ, danielmarjamaki
Reviewed By: zaks.anna, NoQ, danielmarjamaki
Subscribers: cfe-commits, kalev, pwithnall
Differential Revision: https://reviews.llvm.org/D30771
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
cfe/trunk/test/Analysis/gmalloc.c
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=301384&r1=301383&r2=301384&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Wed Apr 26 00:33:14 2017
@@ -177,7 +177,10 @@ public:
II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_g_malloc(nullptr),
II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),
II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
- II_g_free(nullptr), II_g_memdup(nullptr) {}
+ II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
+ II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
+ II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
+ II_g_try_realloc_n(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -241,7 +244,10 @@ private:
*II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
*II_win_wcsdup, *II_g_malloc, *II_g_malloc0,
*II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,
- *II_g_try_realloc, *II_g_free, *II_g_memdup;
+ *II_g_try_realloc, *II_g_free, *II_g_memdup,
+ *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,
+ *II_g_try_malloc_n, *II_g_try_malloc0_n,
+ *II_g_try_realloc_n;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -321,9 +327,12 @@ private:
bool &ReleasedAllocated,
bool ReturnsNullOnFailure = false) const;
- ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
- bool FreesMemOnFailure,
- ProgramStateRef State) const;
+ ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
+ bool FreesMemOnFailure,
+ ProgramStateRef State,
+ bool SuffixWithN = false) const;
+ static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
+ const Expr *BlockBytes);
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State);
@@ -569,6 +578,12 @@ void MallocChecker::initIdentifierInfo(A
II_g_try_realloc = &Ctx.Idents.get("g_try_realloc");
II_g_free = &Ctx.Idents.get("g_free");
II_g_memdup = &Ctx.Idents.get("g_memdup");
+ II_g_malloc_n = &Ctx.Idents.get("g_malloc_n");
+ II_g_malloc0_n = &Ctx.Idents.get("g_malloc0_n");
+ II_g_realloc_n = &Ctx.Idents.get("g_realloc_n");
+ II_g_try_malloc_n = &Ctx.Idents.get("g_try_malloc_n");
+ II_g_try_malloc0_n = &Ctx.Idents.get("g_try_malloc0_n");
+ II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -617,7 +632,10 @@ bool MallocChecker::isCMemFunction(const
FunI == II_g_malloc || FunI == II_g_malloc0 ||
FunI == II_g_realloc || FunI == II_g_try_malloc ||
FunI == II_g_try_malloc0 || FunI == II_g_try_realloc ||
- FunI == II_g_memdup)
+ FunI == II_g_memdup || FunI == II_g_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_realloc_n ||
+ FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n ||
+ FunI == II_g_try_realloc_n)
return true;
}
@@ -767,6 +785,17 @@ llvm::Optional<ProgramStateRef> MallocCh
return None;
}
+SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
+ const Expr *BlockBytes) {
+ SValBuilder &SB = C.getSValBuilder();
+ SVal BlocksVal = C.getSVal(Blocks);
+ SVal BlockBytesVal = C.getSVal(BlockBytes);
+ ProgramStateRef State = C.getState();
+ SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
+ SB.getContext().getSizeType());
+ return TotalSize;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
@@ -813,10 +842,10 @@ void MallocChecker::checkPostStmt(const
State = ProcessZeroAllocation(C, CE, 0, State);
} else if (FunI == II_realloc || FunI == II_g_realloc ||
FunI == II_g_try_realloc) {
- State = ReallocMem(C, CE, false, State);
+ State = ReallocMemAux(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
- State = ReallocMem(C, CE, true, State);
+ State = ReallocMemAux(C, CE, true, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_calloc) {
State = CallocMem(C, CE, State);
@@ -874,6 +903,25 @@ void MallocChecker::checkPostStmt(const
return;
State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 1, State);
+ } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ if (CE->getNumArgs() < 2)
+ return;
+ SVal Init = UndefinedVal();
+ if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ SValBuilder &SB = C.getSValBuilder();
+ Init = SB.makeZeroVal(SB.getContext().CharTy);
+ }
+ SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
+ State = MallocMemAux(C, CE, TotalSize, Init, State);
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) {
+ if (CE->getNumArgs() < 3)
+ return;
+ State = ReallocMemAux(C, CE, false, State, true);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ State = ProcessZeroAllocation(C, CE, 2, State);
}
}
@@ -1976,14 +2024,17 @@ void MallocChecker::ReportUseZeroAllocat
}
}
-ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
- const CallExpr *CE,
- bool FreesOnFail,
- ProgramStateRef State) const {
+ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ bool FreesOnFail,
+ ProgramStateRef State,
+ bool SuffixWithN) const {
if (!State)
return nullptr;
- if (CE->getNumArgs() < 2)
+ if (SuffixWithN && CE->getNumArgs() < 3)
+ return nullptr;
+ else if (CE->getNumArgs() < 2)
return nullptr;
const Expr *arg0Expr = CE->getArg(0);
@@ -1998,20 +2049,19 @@ ProgramStateRef MallocChecker::ReallocMe
DefinedOrUnknownSVal PtrEQ =
svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull());
- // Get the size argument. If there is no size arg then give up.
+ // Get the size argument.
const Expr *Arg1 = CE->getArg(1);
- if (!Arg1)
- return nullptr;
// Get the value of the size argument.
- SVal Arg1ValG = State->getSVal(Arg1, LCtx);
- if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
+ SVal TotalSize = State->getSVal(Arg1, LCtx);
+ if (SuffixWithN)
+ TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
+ if (!TotalSize.getAs<DefinedOrUnknownSVal>())
return nullptr;
- DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
- svalBuilder.evalEQ(State, Arg1Val,
+ svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(),
svalBuilder.makeIntValWithPtrWidth(0, false));
ProgramStateRef StatePtrIsNull, StatePtrNotNull;
@@ -2025,8 +2075,8 @@ ProgramStateRef MallocChecker::ReallocMe
// 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, CE->getArg(1),
+ if (PrtIsNull && !SizeIsZero) {
+ ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize,
UndefinedVal(), StatePtrIsNull);
return stateMalloc;
}
@@ -2059,7 +2109,7 @@ ProgramStateRef MallocChecker::ReallocMe
if (ProgramStateRef stateFree =
FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
- ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
+ ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
UnknownVal(), stateFree);
if (!stateRealloc)
return nullptr;
@@ -2090,12 +2140,8 @@ ProgramStateRef MallocChecker::CallocMem
return nullptr;
SValBuilder &svalBuilder = C.getSValBuilder();
- const LocationContext *LCtx = C.getLocationContext();
- SVal count = State->getSVal(CE->getArg(0), LCtx);
- SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
- SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
- svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
+ SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
return MallocMemAux(C, CE, TotalSize, zeroVal, State);
}
Modified: cfe/trunk/test/Analysis/gmalloc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/gmalloc.c?rev=301384&r1=301383&r2=301384&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/gmalloc.c (original)
+++ cfe/trunk/test/Analysis/gmalloc.c Wed Apr 26 00:33:14 2017
@@ -13,6 +13,12 @@ gpointer g_realloc(gpointer mem, gsize n
gpointer g_try_malloc(gsize n_bytes);
gpointer g_try_malloc0(gsize n_bytes);
gpointer g_try_realloc(gpointer mem, gsize n_bytes);
+gpointer g_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
void g_free(gpointer mem);
gpointer g_memdup(gconstpointer mem, guint byte_size);
@@ -25,6 +31,12 @@ void f1() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
g_free(g1);
g_free(g2);
@@ -38,6 +50,12 @@ void f2() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
g_free(g1);
g_free(g2);
@@ -52,8 +70,100 @@ void f3() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2); // expected-warning{{Potential leak of memory pointed to by 'g4'}}
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+}
+
+void f4() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+}
+
+void f5() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+ g_free(g5);
+}
+
+void f6() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+ g_free(g5);
+ g_free(g6);
+}
+
+void f7() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
g_free(g1);
g_free(g2);
g_free(g3);
+ g_free(g4);
+ g_free(g5);
+ g_free(g6);
+ g_free(g7);
}
More information about the cfe-commits
mailing list