Augment SyzyASAN crash reports with stack traces on alloc/free.
BUG=
Review URL: https://codereview.appspot.com/6817056
git-svn-id: http://sawbuck.googlecode.com/svn/trunk/syzygy@1211 15e8cca8-e42c-11de-a347-f34a4f72eb7d
diff --git a/agent/asan/asan.gyp b/agent/asan/asan.gyp
index ba27a8b..0bd3659 100644
--- a/agent/asan/asan.gyp
+++ b/agent/asan/asan.gyp
@@ -1,10 +1,10 @@
-# Copyright 2012 Google Inc.
+# Copyright 2012 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -54,9 +54,9 @@
'type': 'executable',
'sources': [
'asan_heap_unittest.cc',
- 'asan_shadow_unittest.cc',
'asan_rtl_unittest.cc',
'asan_rtl_unittests_main.cc',
+ 'asan_shadow_unittest.cc',
],
'dependencies': [
'asan_rtl',
diff --git a/agent/asan/asan_heap.cc b/agent/asan/asan_heap.cc
index b396b99..4a3fe45 100644
--- a/agent/asan/asan_heap.cc
+++ b/agent/asan/asan_heap.cc
@@ -23,7 +23,7 @@
namespace {
// Redzone size allocated at the start of every heap block.
-const size_t kRedZoneSize = 32;
+const size_t kRedZoneSize = 32U;
// Utility class which implements an auto lock for a HeapProxy.
class HeapLocker {
@@ -48,6 +48,28 @@
DISALLOW_COPY_AND_ASSIGN(HeapLocker);
};
+// Capture a stack trace and store it in an array of instruction pointer values.
+// @param stack_trace A pointer to a non-allocated array of instruction pointer,
+// *stack_trace is assumed to be equal NULL when we call this function, the
+// array will be dynamically allocated.
+// @param trace_size A pointer to the variable where the stack size should be
+// saved.
+void CaptureStackTrace(void** stack_trace, uint8* trace_size) {
+ DCHECK(stack_trace != NULL);
+ DCHECK(*stack_trace == NULL);
+
+ size_t trace_depth = 0;
+ base::debug::StackTrace trace;
+ const void* temp_trace = trace.Addresses(&trace_depth);
+ *stack_trace = new void*[trace_depth];
+ memcpy(*stack_trace, temp_trace, trace_depth * sizeof(void*));
+
+ // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
+ // the sum of FramesToSkip and FramesToCapture must be less than 63.
+ DCHECK_LE(trace_depth, 62U);
+ *trace_size = static_cast<uint8>(trace_depth);
+}
+
} // namespace
HeapProxy::HeapProxy()
@@ -115,6 +137,9 @@
block->magic_number = kBlockHeaderSignature;
block->size = bytes;
block->state = ALLOCATED;
+ block->alloc_stack_trace = NULL;
+ block->free_stack_trace = NULL;
+ CaptureStackTrace(&block->alloc_stack_trace, &block->alloc_stack_trace_size);
uint8* block_alloc = ToAlloc(block);
Shadow::Unpoison(block_alloc, bytes);
@@ -158,12 +183,12 @@
return false;
}
+ CaptureStackTrace(&block->free_stack_trace, &block->free_stack_trace_size);
DCHECK(ToAlloc(block) == mem);
if (!Shadow::IsAccessible(ToAlloc(block)))
return false;
QuarantineBlock(block);
-
return true;
}
@@ -241,7 +266,6 @@
quarantine_size_ += alloc_size;
// Mark the block as quarantined.
free_block->state = QUARANTINED;
-
// Arbitrarily keep ten megabytes of quarantine per heap.
const size_t kMaxQuarantineSizeBytes = 10 * 1024 * 1024;
@@ -258,6 +282,16 @@
Shadow::Unpoison(free_block, alloc_size);
free_block->state = FREED;
free_block->magic_number = ~kBlockHeaderSignature;
+ if (free_block->alloc_stack_trace != NULL) {
+ delete free_block->alloc_stack_trace;
+ free_block->alloc_stack_trace = NULL;
+ free_block->alloc_stack_trace_size = 0;
+ }
+ if (free_block->free_stack_trace != NULL) {
+ delete free_block->free_stack_trace;
+ free_block->free_stack_trace = NULL;
+ free_block->free_stack_trace_size = 0;
+ }
DCHECK_NE(kBlockHeaderSignature, free_block->magic_number);
::HeapFree(heap_, 0, free_block);
@@ -303,7 +337,6 @@
BadAccessKind bad_access_kind) {
DCHECK(addr != NULL);
DCHECK(header != NULL);
-
uint8* block_alloc = ToAlloc(header);
int offset = 0;
char* offset_relativity = "";
@@ -332,6 +365,20 @@
header->size,
block_alloc,
block_alloc + header->size);
+ if (header->free_stack_trace != NULL) {
+ fprintf(stderr, "freed here:\n");
+ base::debug::StackTrace alloc_trace(
+ static_cast<const void* const*>(header->free_stack_trace),
+ header->free_stack_trace_size);
+ alloc_trace.PrintBacktrace();
+ }
+ if (header->alloc_stack_trace != NULL) {
+ fprintf(stderr, "previously allocated here:\n");
+ base::debug::StackTrace alloc_trace(
+ static_cast<const void* const*>(header->alloc_stack_trace),
+ header->alloc_stack_trace_size);
+ alloc_trace.PrintBacktrace();
+ }
Shadow::PrintShadowMemoryForAddress(addr);
}
diff --git a/agent/asan/asan_heap.h b/agent/asan/asan_heap.h
index 692676d..5d7cfc1 100644
--- a/agent/asan/asan_heap.h
+++ b/agent/asan/asan_heap.h
@@ -20,6 +20,7 @@
#include <windows.h> // NOLINT
+#include "base/debug/stack_trace.h"
#include "base/synchronization/lock.h"
#include "syzygy/agent/common/dlist.h"
@@ -96,11 +97,14 @@
};
// Every allocated block starts with a BlockHeader.
- // TODO(sebmarchand): Add field for stack trace etc.
struct BlockHeader {
size_t magic_number;
size_t size;
BlockState state;
+ void* alloc_stack_trace;
+ void* free_stack_trace;
+ uint8 alloc_stack_trace_size;
+ uint8 free_stack_trace_size;
};
// Returns the block header for an alloc.
@@ -179,7 +183,7 @@
// Total size of blocks in quarantine.
size_t quarantine_size_; // Under lock_.
- // The entry linking to us.
+ // The entry linking to us.
LIST_ENTRY list_entry_;
};