[cfe-commits] [patch] Catch a few simple misuses of free()
Jordy Rose
jediknil at belkadan.com
Thu Jun 3 20:28:54 PDT 2010
Catch free()s on non-regions and regions known to be not from malloc() (by
checking the memory space).
(This actually arose because I was trying to test branches with bad
free()s and was surprised they weren't warning.)
BTW: even though I was granted commit access, I assume "[patch]" is still
a good way to introduce these small changes.
-------------- next part --------------
Index: lib/Checker/MallocChecker.cpp
===================================================================
--- lib/Checker/MallocChecker.cpp (revision 105311)
+++ lib/Checker/MallocChecker.cpp (working copy)
@@ -59,11 +59,14 @@
BuiltinBug *BT_DoubleFree;
BuiltinBug *BT_Leak;
BuiltinBug *BT_UseFree;
+ BuiltinBug *BT_FreeNonRegion;
+ BuiltinBug *BT_FreeNonMalloc;
IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
public:
MallocChecker()
- : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0),
+ : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_FreeNonRegion(0),
+ BT_FreeNonMalloc(0),
II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
static void *getTag();
bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
@@ -197,12 +200,52 @@
if (ArgVal.isZeroConstant())
return state;
- SymbolRef Sym = ArgVal.getAsLocSymbol();
-
+ const MemRegion *R = ArgVal.getAsRegion();
+ if (!R) {
+
+ ExplodedNode *N = C.GenerateSink();
+ if (N) {
+ if (!BT_FreeNonRegion)
+ BT_FreeNonRegion = new BuiltinBug("Bad free",
+ "Argument to free() is not a valid location");
+ BugReport *R = new BugReport(*BT_FreeNonRegion,
+ BT_FreeNonRegion->getDescription(), N);
+ C.EmitReport(R);
+ }
+ return NULL;
+ }
+
+ R = R->StripCasts();
+
+ const MemSpaceRegion *MS = R->getMemorySpace();
+ if (!isa<UnknownSpaceRegion>(MS)) {
+ // Conjured symbols are all unknown-space right now,
+ // but malloc() regions should be in HeapSpaceRegion.
+ // Of course, free() can work on memory allocated outside the current
+ // function, so UnknownSpaceRegion is always a possibility.
+
+ ExplodedNode *N = C.GenerateSink();
+ if (N) {
+ if (!BT_FreeNonMalloc)
+ BT_FreeNonMalloc = new BuiltinBug("Bad free",
+ "Try to free a memory block that was not allocated "
+ "by malloc()");
+ // FIXME: should show where the memory came from
+ BugReport *R = new BugReport(*BT_FreeNonMalloc,
+ BT_FreeNonMalloc->getDescription(), N);
+ C.EmitReport(R);
+ }
+ return NULL;
+ }
+
+ const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
// Various cases could lead to non-symbol values here.
- if (!Sym)
+ // For now, ignore them.
+ if (!SR)
return state;
+ SymbolRef Sym = SR->getSymbol();
+
const RefState *RS = state->get<RegionState>(Sym);
// If the symbol has not been tracked, return. This is possible when free() is
Index: test/Analysis/free.c
===================================================================
--- test/Analysis/free.c (revision 0)
+++ test/Analysis/free.c (revision 0)
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+void free(void *);
+
+void t1 () {
+ int a[] = { 1 };
+ free(a); // expected-warning {{not allocated by malloc()}}
+}
+
+void t2 () {
+ int a = 1;
+ free(&a); // expected-warning {{not allocated by malloc()}}
+}
+
+void t3 () {
+ static int a[] = { 1 };
+ free(a); // expected-warning {{not allocated by malloc()}}
+}
+
+void t4 (char *x) {
+ free(x); // no-warning
+}
+
+void t5 () {
+ extern char *ptr();
+ free(ptr()); // no-warning
+}
+
+void t6 () {
+ free((void*)1000); // expected-warning {{not a valid location}}
+}
+
+void t7 (char **x) {
+ free(*x); // no-warning
+}
+
+void t8 (char **x) {
+ // ugh
+ free((*x)+8); // no-warning
+}
+
+void t9 () {
+label:
+ free(&&label); // expected-warning {{not a valid location}}
+}
More information about the cfe-commits
mailing list