Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp	(revision 169960)
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp	(working copy)
@@ -705,6 +705,17 @@
     return 0;
   }
   
+  // Check if the memory location being freed is the actual location
+  // allocated, or an offset
+  
+  RegionOffset offset = R->getAsOffset();
+  if(   offset.isValid() 
+     && offset.hasSymbolicOffset() == false 
+     && offset.getOffset() != 0) {
+    ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+    return 0;
+  }
+  
   const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
   // Various cases could lead to non-symbol values here.
   // For now, ignore them.
@@ -857,6 +868,12 @@
     
     const MemRegion *MR = ArgVal.getAsRegion();
     if (MR) {
+      
+      // Get the offset into the memory region before
+      // getting the super region, as retrieving the 
+      // super region will ignore the offset.
+      RegionOffset offset = MR->getAsOffset();
+
       while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR))
         MR = ER->getSuperRegion();
       
@@ -869,6 +886,13 @@
           os << ", which is not memory allocated by malloc()";
         else
           os << "not memory allocated by malloc()";
+        
+        if(   offset.isValid() 
+           && offset.hasSymbolicOffset() == false 
+           && offset.getOffset() != 0) {
+          os << "; the memory location passed is an offset of an allocated location ";
+        }
+        
       }
     } else {
       os << "Argument to free() is ";
Index: test/Analysis/malloc.c
===================================================================
--- test/Analysis/malloc.c	(revision 169960)
+++ test/Analysis/malloc.c	(working copy)
@@ -1041,6 +1041,57 @@
   return strdup(strdup(str)); // expected-warning{{leak}}
 }
 
+void freePostIncrementedPointer() {
+  char *r = malloc(sizeof(char));
+  r++;
+  free(r); // expected-warning {{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+} 
+
+void freePreIncrementedPointer() {
+  char *r = malloc(sizeof(char));
+  ++r;
+  free(r); // expected-warning {{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+} 
+
+void freePostDecrementedPointer() {
+  char *r = malloc(sizeof(char));
+  r--;
+  free(r); // expected-warning {{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+} 
+
+void freePreDecrementedPointer() {
+  char *r = malloc(sizeof(char));
+  --r;
+  free(r); // expected-warning {{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+} 
+
+void freeOffsetPointer() {
+  char *r = malloc(sizeof(char));
+  r = r - 10;
+  free(r); // expected-warning {{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+}
+
+void freeOffsetPointerFixed() {
+  char *r = malloc(sizeof(char));
+  r = r + 10;
+  free(r-10); // no-warning
+}
+
+void freeOffsetPointerPassedToFunction() {  
+  int *p = malloc(sizeof(int)*2);
+  p[1] = 0;
+  p += 1;
+  myfooint(*p);
+  free(p); // expected-warning {{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+}
+
+int arbitraryInt();
+void freeUnknownOffsetPointer() {
+  char *r = malloc(sizeof(char));
+  r = r + arbitraryInt(); // unable to reason about what the offset might be
+  free(r); // no-warning
+}
+
 // ----------------------------------------------------------------------------
 // False negatives.
 
