aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp30
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp3
-rw-r--r--test/Analysis/malloc-annotations.c3
-rw-r--r--test/Analysis/malloc.c48
4 files changed, 41 insertions, 43 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 4f19c2ee07..d384bc34f9 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1000,10 +1000,11 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "Memory is never released; potential leak";
- if (Region) {
+ // FIXME: Make all region pretty-printing nice enough to show.
+ if (Region && isa<VarRegion>(Region)) {
os << " of memory pointed to by '";
Region->dumpPretty(os);
- os <<'\'';
+ os << '\'';
}
BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
@@ -1117,7 +1118,8 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
return;
// Check if we are returning a symbol.
- SVal RetVal = C.getState()->getSVal(E, C.getLocationContext());
+ ProgramStateRef State = C.getState();
+ SVal RetVal = State->getSVal(E, C.getLocationContext());
SymbolRef Sym = RetVal.getAsSymbol();
if (!Sym)
// If we are returning a field of the allocated struct or an array element,
@@ -1128,16 +1130,18 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
if (const SymbolicRegion *BMR =
dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
Sym = BMR->getSymbol();
- if (!Sym)
- return;
// Check if we are returning freed memory.
- if (checkUseAfterFree(Sym, C, E))
- return;
+ if (Sym)
+ if (checkUseAfterFree(Sym, C, E))
+ return;
- // If this function body is not inlined, check if the symbol is escaping.
- if (C.getLocationContext()->getParent() == 0)
- checkEscape(Sym, E, C);
+ // If this function body is not inlined, stop tracking any returned symbols.
+ if (C.getLocationContext()->getParent() == 0) {
+ State =
+ State->scanReachableSymbols<StopTrackingCallback>(RetVal).getState();
+ C.addTransition(State);
+ }
}
// TODO: Blocks should be either inlined or should call invalidate regions
@@ -1245,12 +1249,6 @@ void MallocChecker::checkBind(SVal loc, SVal val, const Stmt *S,
if (StoredVal != val)
escapes = (state == (state->bindLoc(*regionLoc, val)));
}
- if (!escapes) {
- // Case 4: We do not currently model what happens when a symbol is
- // assigned to a struct field, so be conservative here and let the symbol
- // go. TODO: This could definitely be improved upon.
- escapes = !isa<VarRegion>(regionLoc->getRegion());
- }
}
// If our store can represent the binding and we aren't storing to something
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 9245a70dd2..c20979bddb 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -542,6 +542,9 @@ bool ScanReachableSymbols::scan(SVal val) {
if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
return scan(X->getRegion());
+ if (nonloc::LazyCompoundVal *X = dyn_cast<nonloc::LazyCompoundVal>(&val))
+ return scan(X->getRegion());
+
if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
return scan(X->getLoc());
diff --git a/test/Analysis/malloc-annotations.c b/test/Analysis/malloc-annotations.c
index 089e53132d..1dc0f7837b 100644
--- a/test/Analysis/malloc-annotations.c
+++ b/test/Analysis/malloc-annotations.c
@@ -70,10 +70,9 @@ void af1_c() {
myglobalpointer = my_malloc(12); // no-warning
}
-// TODO: We will be able to handle this after we add support for tracking allocations stored in struct fields.
void af1_d() {
struct stuff mystuff;
- mystuff.somefield = my_malloc(12); // false negative
+ mystuff.somefield = my_malloc(12); // expected-warning{{Memory is never released; potential leak}}
}
// Test that we can pass out allocated memory via pointer-to-pointer.
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 7f5062af45..24fa30baa8 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -513,20 +513,20 @@ void testMalloc() {
int *x = malloc(12);
StructWithPtr St;
St.memP = x;
- arrOfStructs[0] = St;
+ arrOfStructs[0] = St; // no-warning
}
StructWithPtr testMalloc2() {
int *x = malloc(12);
StructWithPtr St;
St.memP = x;
- return St;
+ return St; // no-warning
}
int *testMalloc3() {
int *x = malloc(12);
int *y = x;
- return y;
+ return y; // no-warning
}
void testElemRegion1() {
@@ -926,31 +926,16 @@ int cmpHeapAllocationToUnknown() {
return 0;
}
-// ----------------------------------------------------------------------------
-// False negatives.
-
-// TODO: This requires tracking symbols stored inside the structs/arrays.
-void testMalloc5() {
- StructWithPtr St;
- StructWithPtr *pSt = &St;
- pSt->memP = malloc(12);
-}
-
-// TODO: This is another false negative.
-void testMallocWithParam(int **p) {
- *p = (int*) malloc(sizeof(int));
- *p = 0;
-}
-
-void testMallocWithParam_2(int **p) {
- *p = (int*) malloc(sizeof(int));
-}
-
-// TODO: This should produce a warning, similar to the previous issue.
void localArrayTest() {
char *p = (char*)malloc(12);
char *ArrayL[12];
- ArrayL[0] = p;
+ ArrayL[0] = p; // expected-warning {{leak}}
+}
+
+void localStructTest() {
+ StructWithPtr St;
+ StructWithPtr *pSt = &St;
+ pSt->memP = malloc(12); // expected-warning{{Memory is never released; potential leak}}
}
// Test double assignment through integers.
@@ -1019,3 +1004,16 @@ int* reallocButNoMalloc(struct HasPtr *a, int c, int size) {
return 0; // expected-warning{{Memory is never released; potential leak}}
return a->p;
}
+
+// ----------------------------------------------------------------------------
+// False negatives.
+
+// TODO: This is another false negative.
+void testMallocWithParam(int **p) {
+ *p = (int*) malloc(sizeof(int));
+ *p = 0;
+}
+
+void testMallocWithParam_2(int **p) {
+ *p = (int*) malloc(sizeof(int));
+}