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);
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,
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
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
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() {
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.
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));
+}