xiangzhai updated this revision to Diff 89331.
xiangzhai added a comment.
Hi Anna,
I added **svalBinMulOp** to take BO_Mul evalBinOp for g_malloc_n's two
arguments: CE->getArg(0) and CE->getArg(1), so it does **NOT** need to change
**MallocMemAux** any more, but just use it in this way:
State = MallocMemAux(C, CE,
svalBinMulOp(C, CE->getArg(0),
CE->getArg(1), State),
UndefinedVal(), State);
And I also added **ReallocMemN** for g_realloc_n, it also use svalBinMulOp for
**!StateSizeIsZero** check.
Please indicate my mistake, thanks a lot!
Regards,
Leslie Zhai
Repository:
rL LLVM
https://reviews.llvm.org/D28348
Files:
lib/StaticAnalyzer/Checkers/MallocChecker.cpp
test/Analysis/gmalloc.c
Index: test/Analysis/gmalloc.c
===================================================================
--- test/Analysis/gmalloc.c
+++ test/Analysis/gmalloc.c
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify %s
+
+#include "Inputs/system-header-simulator.h"
+
+typedef void* gpointer;
+typedef const void* gconstpointer;
+typedef unsigned long gsize;
+typedef unsigned int guint;
+
+gpointer g_malloc(gsize n_bytes);
+gpointer g_malloc0(gsize n_bytes);
+gpointer g_realloc(gpointer mem, gsize n_bytes);
+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);
+
+static const gsize n_bytes = 1024;
+
+void f1() {
+ 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));
+
+ g_free(g1);
+ g_free(g2);
+ g_free(g2); // expected-warning{{Attempt to free released memory}}
+}
+
+void f2() {
+ 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));
+
+ g_free(g1);
+ g_free(g2);
+ g_free(g3);
+ g3 = g_memdup(g3, n_bytes); // expected-warning{{Use of memory after it is freed}}
+}
+
+void f3() {
+ 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); // 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);
+}
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -174,7 +174,13 @@
II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
II_if_nameindex(nullptr), II_if_freenameindex(nullptr),
- II_wcsdup(nullptr), II_win_wcsdup(nullptr) {}
+ 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_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),
+ II_g_free(nullptr), II_g_memdup(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -236,7 +242,12 @@
*II_realloc, *II_calloc, *II_valloc, *II_reallocf,
*II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
*II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
- *II_win_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_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,
+ *II_g_free, *II_g_memdup;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -319,6 +330,11 @@
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
bool FreesMemOnFailure,
ProgramStateRef State) const;
+ SVal svalBinMulOp(CheckerContext &C, SVal SBlocks, SVal SBlockBytes,
+ ProgramStateRef State);
+ ProgramStateRef ReallocMemN(CheckerContext &C, const CallExpr *CE,
+ bool FreesMemOnFailure,
+ ProgramStateRef State) const;
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State);
@@ -554,6 +570,22 @@
II_win_strdup = &Ctx.Idents.get("_strdup");
II_win_wcsdup = &Ctx.Idents.get("_wcsdup");
II_win_alloca = &Ctx.Idents.get("_alloca");
+
+ // Glib
+ II_g_malloc = &Ctx.Idents.get("g_malloc");
+ II_g_malloc0 = &Ctx.Idents.get("g_malloc0");
+ II_g_realloc = &Ctx.Idents.get("g_realloc");
+ II_g_try_malloc = &Ctx.Idents.get("g_try_malloc");
+ II_g_try_malloc0 = &Ctx.Idents.get("g_try_malloc0");
+ II_g_try_realloc = &Ctx.Idents.get("g_try_realloc");
+ II_g_malloc_n = &Ctx.Idents.get("g_malloc_n"); // unimplemented XXX_n yet
+ 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");
+ II_g_free = &Ctx.Idents.get("g_free");
+ II_g_memdup = &Ctx.Idents.get("g_memdup");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -589,15 +621,23 @@
initIdentifierInfo(C);
if (Family == AF_Malloc && CheckFree) {
- if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
+ if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf ||
+ FunI == II_g_free)
return true;
}
if (Family == AF_Malloc && CheckAlloc) {
if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
FunI == II_win_strdup || FunI == II_strndup || FunI == II_wcsdup ||
- FunI == II_win_wcsdup || FunI == II_kmalloc)
+ FunI == II_win_wcsdup || FunI == II_kmalloc ||
+ 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_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 ||
+ FunI == II_g_memdup)
return true;
}
@@ -747,6 +787,19 @@
return None;
}
+SVal MallocChecker::svalBinMulOp(CheckerContext &C,
+ SVal SBlocks,
+ SVal SBlockBytes,
+ ProgramStateRef State) {
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal nBlocks = State->getSVal(SBlocks, LCtx);
+ SVal nBlockBytes = State->getSVal(SBlockBytes, LCtx);
+ SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, nBlocks, nBlockBytes,
+ svalBuilder.getContext().getSizeType());
+ return TotalSize;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
@@ -762,7 +815,8 @@
initIdentifierInfo(C.getASTContext());
IdentifierInfo *FunI = FD->getIdentifier();
- if (FunI == II_malloc) {
+ if (FunI == II_malloc || FunI == II_g_malloc || FunI == II_g_malloc0 ||
+ FunI == II_g_try_malloc || FunI == II_g_try_malloc0) {
if (CE->getNumArgs() < 1)
return;
if (CE->getNumArgs() < 3) {
@@ -791,7 +845,8 @@
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (FunI == II_realloc) {
+ } else if (FunI == II_realloc || FunI == II_g_realloc ||
+ FunI == II_g_try_realloc) {
State = ReallocMem(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
@@ -801,7 +856,7 @@
State = CallocMem(C, CE, State);
State = ProcessZeroAllocation(C, CE, 0, State);
State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_free) {
+ } else if (FunI == II_free || FunI == II_g_free) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup || FunI == II_win_strdup ||
FunI == II_wcsdup || FunI == II_win_wcsdup) {
@@ -841,6 +896,26 @@
AF_IfNameIndex);
} else if (FunI == II_if_freenameindex) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+ } else if (FunI == II_g_malloc_n || FunI == II_g_malloc0_n ||
+ FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n) {
+ if (CE->getNumArgs() < 2)
+ return;
+ State = MallocMemAux(C, CE,
+ svalBinMulOp(C, CE->getArg(0), CE->getArg(1), State),
+ UndefinedVal(), 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 = ReallocMemN(C, CE, false, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ State = ProcessZeroAllocation(C, CE, 2, State);
+ } else if (FunI == II_g_memdup) {
+ if (CE->getNumArgs() < 2)
+ return;
+ State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
}
}
@@ -2048,6 +2123,116 @@
return nullptr;
}
+ProgramStateRef MallocChecker::ReallocMemN(CheckerContext &C,
+ const CallExpr *CE,
+ bool FreesOnFail,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
+ if (CE->getNumArgs() < 3)
+ return nullptr;
+
+ const Expr *arg0Expr = CE->getArg(0);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal Arg0Val = State->getSVal(arg0Expr, LCtx);
+ if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
+ return nullptr;
+ DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
+
+ SValBuilder &svalBuilder = C.getSValBuilder();
+
+ DefinedOrUnknownSVal PtrEQ =
+ svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull());
+
+ // Get the size argument. If there is no size arg then give up.
+ const Expr *Arg1 = CE->getArg(1);
+ const Expr *Arg2 = CE->getArg(2);
+ if (!Arg1 || !Arg2)
+ return nullptr;
+
+ // Get the value of the size argument.
+ SVal Arg1ValG = State->getSVal(Arg1, LCtx);
+ SVal Arg2ValG = State->getSVal(Arg2, LCtx);
+ if (!Arg1ValG.getAs<DefinedOrUnknownSVal>() || !Arg2ValG.getAs<DefinedOrUnknownSVal>())
+ return nullptr;
+ SVal TotalSizeG = svalBinMulOp(C, Arg1ValG, Arg2ValG, State);
+ DefinedOrUnknownSVal TotalSize = TotalSizeG.castAs<DefinedOrUnknownSVal>();
+
+ // Compare the size argument to 0.
+ DefinedOrUnknownSVal SizeZero =
+ svalBuilder.evalEQ(State, TotalSize,
+ svalBuilder.makeIntValWithPtrWidth(0, false));
+
+ ProgramStateRef StatePtrIsNull, StatePtrNotNull;
+ std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
+ ProgramStateRef StateSizeIsZero, StateSizeNotZero;
+ std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
+ // We only assume exceptional states if they are definitely true; if the
+ // state is under-constrained, assume regular realloc behavior.
+ bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
+ bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
+
+ // 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,
+ svalBinMulOp(C, CE->getArg(1), CE->getArg(2), State),
+ UndefinedVal(), StatePtrIsNull);
+ return stateMalloc;
+ }
+
+ if (PrtIsNull && SizeIsZero)
+ return State;
+
+ // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
+ assert(!PrtIsNull);
+ SymbolRef FromPtr = arg0Val.getAsSymbol();
+ SVal RetVal = State->getSVal(CE, LCtx);
+ SymbolRef ToPtr = RetVal.getAsSymbol();
+ if (!FromPtr || !ToPtr)
+ return nullptr;
+
+ bool ReleasedAllocated = false;
+
+ // If the size is 0, free the memory.
+ if (SizeIsZero)
+ if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0,
+ false, ReleasedAllocated)){
+ // The semantics of the return value are:
+ // 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.
+ return stateFree;
+ }
+
+ // Default behavior.
+ if (ProgramStateRef stateFree =
+ FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
+
+ ProgramStateRef stateRealloc = MallocMemAux(C, CE,
+ svalBinMulOp(C, CE->getArg(1), CE->getArg(2), State),
+ UnknownVal(), stateFree);
+ if (!stateRealloc)
+ return nullptr;
+
+ ReallocPairKind Kind = RPToBeFreedAfterFailure;
+ if (FreesOnFail)
+ Kind = RPIsFreeOnFailure;
+ else if (!ReleasedAllocated)
+ Kind = RPDoNotTrackAfterFailure;
+
+ // Record the info about the reallocated symbol so that we could properly
+ // process failed reallocation.
+ stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
+ ReallocPair(FromPtr, Kind));
+ // The reallocated symbol should stay alive for as long as the new symbol.
+ C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
+ return stateRealloc;
+ }
+ return nullptr;
+}
+
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State) {
if (!State)
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits