diff options
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 30 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ProgramState.cpp | 3 | ||||
-rw-r--r-- | test/Analysis/malloc-annotations.c | 3 | ||||
-rw-r--r-- | test/Analysis/malloc.c | 48 |
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)); +} |