summaryrefslogtreecommitdiffstats
path: root/runtime/stack.cc
diff options
context:
space:
mode:
authorDave Allison <dallison@google.com>2014-03-27 15:10:22 -0700
committerDave Allison <dallison@google.com>2014-03-31 18:04:08 -0700
commitf943914730db8ad2ff03d49a2cacd31885d08fd7 (patch)
tree885a781e5f8bd852e2c1615108ae7b17576a6567 /runtime/stack.cc
parentcfd5acf281b0c509f86b13d73c6a8dfa3ea9922c (diff)
downloadart-f943914730db8ad2ff03d49a2cacd31885d08fd7.zip
art-f943914730db8ad2ff03d49a2cacd31885d08fd7.tar.gz
art-f943914730db8ad2ff03d49a2cacd31885d08fd7.tar.bz2
Implement implicit stack overflow checks
This also fixes some failing run tests due to missing null pointer markers. The implementation of the implicit stack overflow checks introduces the ability to have a gap in the stack that is skipped during stack walk backs. This gap is protected against read/write and is used to trigger a SIGSEGV at function entry if the stack will overflow. Change-Id: I0c3e214c8b87dc250cf886472c6d327b5d58653e
Diffstat (limited to 'runtime/stack.cc')
-rw-r--r--runtime/stack.cc61
1 files changed, 57 insertions, 4 deletions
diff --git a/runtime/stack.cc b/runtime/stack.cc
index c33d1ab..ab3bd85 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -16,6 +16,7 @@
#include "stack.h"
+#include "base/hex_dump.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
@@ -23,6 +24,7 @@
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "runtime.h"
+#include "thread.h"
#include "thread_list.h"
#include "throw_location.h"
#include "verify_object-inl.h"
@@ -30,6 +32,14 @@
namespace art {
+// Define a piece of memory, the address of which can be used as a marker
+// for the gap in the stack added during stack overflow handling.
+static uint32_t stack_overflow_object;
+
+// The stack overflow gap marker is simply a valid unique address.
+void* stack_overflow_gap_marker = &stack_overflow_object;
+
+
mirror::Object* ShadowFrame::GetThisObject() const {
mirror::ArtMethod* m = GetMethod();
if (m->IsStatic()) {
@@ -294,20 +304,56 @@ void StackVisitor::WalkStack(bool include_transitions) {
CHECK_EQ(cur_depth_, 0U);
bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
uint32_t instrumentation_stack_depth = 0;
+
+ bool kDebugStackWalk = false;
+ bool kDebugStackWalkVeryVerbose = false; // The name says it all.
+
+ if (kDebugStackWalk) {
+ LOG(INFO) << "walking stack";
+ }
for (const ManagedStack* current_fragment = thread_->GetManagedStack(); current_fragment != NULL;
current_fragment = current_fragment->GetLink()) {
cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
cur_quick_frame_ = current_fragment->GetTopQuickFrame();
cur_quick_frame_pc_ = current_fragment->GetTopQuickFramePc();
+ if (kDebugStackWalkVeryVerbose) {
+ LOG(INFO) << "cur_quick_frame: " << cur_quick_frame_;
+ LOG(INFO) << "cur_quick_frame_pc: " << std::hex << cur_quick_frame_pc_;
+ }
+
if (cur_quick_frame_ != NULL) { // Handle quick stack frames.
// Can't be both a shadow and a quick fragment.
DCHECK(current_fragment->GetTopShadowFrame() == NULL);
mirror::ArtMethod* method = *cur_quick_frame_;
while (method != NULL) {
- SanityCheckFrame();
- bool should_continue = VisitFrame();
- if (UNLIKELY(!should_continue)) {
- return;
+ // Check for a stack overflow gap marker.
+ if (method == reinterpret_cast<mirror::ArtMethod*>(stack_overflow_gap_marker)) {
+ // Marker for a stack overflow. This is followed by the offset from the
+ // current SP to the next frame. There is a gap in the stack here. Jump
+ // the gap silently.
+ // Caveat coder: the layout of the overflow marker depends on the architecture.
+ // The first element is address sized (8 bytes on a 64 bit machine). The second
+ // element is 32 bits. So be careful with those address calculations.
+
+ // Get the address of the offset, just beyond the marker pointer.
+ byte* gapsizeaddr = reinterpret_cast<byte*>(cur_quick_frame_) + sizeof(uintptr_t);
+ uint32_t gap = *reinterpret_cast<uint32_t*>(gapsizeaddr);
+ CHECK_GT(gap, Thread::kStackOverflowProtectedSize);
+ mirror::ArtMethod** next_frame = reinterpret_cast<mirror::ArtMethod**>(
+ reinterpret_cast<byte*>(gapsizeaddr) + gap);
+ if (kDebugStackWalk) {
+ LOG(INFO) << "stack overflow marker hit, gap: " << gap << ", next_frame: " <<
+ next_frame;
+ }
+ cur_quick_frame_ = next_frame;
+ method = *next_frame;
+ CHECK(method != nullptr);
+ } else {
+ SanityCheckFrame();
+ bool should_continue = VisitFrame();
+ if (UNLIKELY(!should_continue)) {
+ return;
+ }
}
if (context_ != NULL) {
context_->FillCalleeSaves(*this);
@@ -317,6 +363,9 @@ void StackVisitor::WalkStack(bool include_transitions) {
size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
+ if (kDebugStackWalkVeryVerbose) {
+ LOG(INFO) << "frame size: " << frame_size << ", return_pc: " << std::hex << return_pc;
+ }
if (UNLIKELY(exit_stubs_installed)) {
// While profiling, the return pc is restored from the side stack, except when walking
// the stack for an exception where the side stack will be unwound in VisitFrame.
@@ -349,6 +398,10 @@ void StackVisitor::WalkStack(bool include_transitions) {
cur_quick_frame_ = reinterpret_cast<mirror::ArtMethod**>(next_frame);
cur_depth_++;
method = *cur_quick_frame_;
+ if (kDebugStackWalkVeryVerbose) {
+ LOG(INFO) << "new cur_quick_frame_: " << cur_quick_frame_;
+ LOG(INFO) << "new cur_quick_frame_pc_: " << std::hex << cur_quick_frame_pc_;
+ }
}
} else if (cur_shadow_frame_ != NULL) {
do {