diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index c6a07a0..c2bc999 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -710,8 +710,10 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
     ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
     return 0;
   }
+
+  const MemRegion *Rbase = R->getBaseRegion();
   
-  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Rbase);
   // Various cases could lead to non-symbol values here.
   // For now, ignore them.
   if (!SR)
@@ -743,6 +745,17 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
     return 0;
   }
 
+  // Check if the memory location being freed is the actual location
+  // allocated, or an offset.
+  RegionOffset offset = R->getAsOffset();
+  if (RS && RS->isAllocated() &&
+      offset.isValid() &&
+      offset.hasSymbolicOffset() == false &&
+      offset.getOffset() != 0) {
+    ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+    return 0;
+  }
+
   ReleasedAllocated = (RS != 0);
 
   // Clean out the info on previous call to free return info.
@@ -863,6 +876,11 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
     
     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();
       
@@ -875,6 +893,13 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
           os << ", which is not memory allocated by malloc()";
         else
           os << "not memory allocated by malloc()";
+
+        if (offset.isValid()
+           && !offset.hasSymbolicOffset()
+           && offset.getOffset() != 0) {
+          os << "; the memory location passed is an offset of an allocated location";
+        }
+
       }
     } else {
       os << "Argument to free() is ";
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 3e5f914..539e42d 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1041,6 +1041,81 @@ char *testLeakWithinReturn(char *str) {
   return strdup(strdup(str)); // expected-warning{{leak}}
 }
 
+int *testOffsetAllocate(size_t size) {
+  int *memoryBlock = (int *)malloc(size + sizeof(int));
+  return &memoryBlock[1]; // no-warning
+}
+
+void testOffsetDeallocate(int *memoryBlock) {
+  free(&memoryBlock[-1]);  // no-warning
+}
+
+void testOffsetOfRegionFreed() {
+  int * array = malloc(sizeof(int)*2);
+  array += 1;
+  free(&array[0]); // expected-warning{{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+}
+
+void testOffsetOfRegionFreed2() {
+  int *p = malloc(12);
+  p += 1;
+  free(p); // expected-warning{{Argument to free() is not memory allocated by malloc(); the memory location passed is an offset of an allocated location}}
+}
+
+void testOffsetOfRegionFreed3() {
+  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 testOffsetOfRegionFreedAfterFunctionCall() {
+  int *p = malloc(sizeof(int)*2);
+  p += 1;
+  myfoo(p);
+  free(p); // no-warning
+}
+
+void testFixManipulatedPointerBeforeFree() {
+  int * array = malloc(sizeof(int)*2);
+  array += 1;
+  free(&array[-1]); // no-warning
+}
+
+void testFixManipulatedPointerBeforeFree2() {
+  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); // not passing the pointer, only a value pointed by pointer
+  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
+}
+
+void testFreeNonMallocPointerWithOffset() {
+  char c;
+  char * r = &c;
+  r = r + 10;
+  free(r-10); // expected-warning {{Argument to free() is the address of the local variable 'c', which is not memory allocated by malloc()}}
+}
+
+void testOffsetZeroDoubleFree() {
+  int *array = malloc(sizeof(int)*2);
+  int *p = &array[0];
+  free(p);
+  free(&array[0]); // expected-warning{{Attempt to free released memory}}
+}
+
 // ----------------------------------------------------------------------------
 // False negatives.
 
