Fix a bug in Shadow::IsBeginningOfBlockBody

The beginning of a block might be in its trailer in the case of a 0 bytes block.

BUG=
R=chrisha@chromium.org

Review URL: https://codereview.appspot.com/133110044

git-svn-id: http://sawbuck.googlecode.com/svn/trunk@2276 15e8cca8-e42c-11de-a347-f34a4f72eb7d
diff --git a/syzygy/agent/asan/shadow.cc b/syzygy/agent/asan/shadow.cc
index a56d36f..9b27dfc 100644
--- a/syzygy/agent/asan/shadow.cc
+++ b/syzygy/agent/asan/shadow.cc
@@ -234,9 +234,15 @@
 
 bool Shadow::IsBeginningOfBlockBody(const void* addr) {
   DCHECK_NE(static_cast<void*>(NULL), addr);
-  if (IsLeftRedzone(addr) || IsRightRedzone(addr))
-    return false;
-  return IsLeftRedzone(reinterpret_cast<const uint8*>(addr) - 1);
+  // If the block has a non-zero body size then the beginning of the body will
+  // be accessible or tagged as freed.
+  // If the block has an empty body then the beginning of the body will be a
+  // right redzone.
+  if (IsAccessible(addr) || IsRightRedzone(addr) ||
+      GetShadowMarkerForAddress(addr) == kHeapFreedMarker) {
+    return IsLeftRedzone(reinterpret_cast<const uint8*>(addr) - 1);
+  }
+  return false;
 }
 
 void Shadow::CloneShadowRange(const void* src_pointer,
diff --git a/syzygy/agent/asan/shadow_unittest.cc b/syzygy/agent/asan/shadow_unittest.cc
index b3d7a81..14549f0 100644
--- a/syzygy/agent/asan/shadow_unittest.cc
+++ b/syzygy/agent/asan/shadow_unittest.cc
@@ -324,7 +324,6 @@
   Shadow::Unpoison(info.block, info.block_size);
 }
 
-
 namespace {
 
 void TestBlockInfoFromShadow(const BlockLayout& outer,
@@ -430,6 +429,30 @@
   Shadow::Unpoison(data.get(), data_size);
 }
 
+TEST(ShadowTest, IsBeginningOfBlockBodyForBlockOfSizeZero) {
+  BlockLayout l = {};
+  BlockPlanLayout(kShadowRatio, kShadowRatio, 0, 0, 0, &l);
+
+  size_t data_size = l.block_size;
+  scoped_ptr<uint8> data(new uint8[data_size]);
+
+  BlockInfo block_info = {};
+  BlockInitialize(l, data.get(), false, &block_info);
+
+  Shadow::PoisonAllocatedBlock(block_info);
+
+  EXPECT_TRUE(Shadow::IsBeginningOfBlockBody(block_info.body));
+  EXPECT_FALSE(Shadow::IsBeginningOfBlockBody(data.get()));
+
+  block_info.header->state = QUARANTINED_BLOCK;
+  Shadow::MarkAsFreed(block_info.body, block_info.body_size);
+
+  EXPECT_TRUE(Shadow::IsBeginningOfBlockBody(block_info.body));
+  EXPECT_FALSE(Shadow::IsBeginningOfBlockBody(data.get()));
+
+  Shadow::Unpoison(data.get(), data_size);
+}
+
 TEST(ShadowWalkerTest, WalksNonNestedBlocks) {
   BlockLayout l = {};
   BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l);