Fix stack overflow handling.

Change-Id: I829001fdf52d33fdeac599ba9225e9f8a40b7881
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index 71fd33c..d3ab039 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -942,11 +942,13 @@
                     ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
                 break;
             case kThrowStackOverflow:
-                funcOffset =
-                    ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
+                funcOffset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
                 // Restore stack alignment
-                opRegImm(cUnit, kOpAdd, rSP,
-                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
+#if !defined(TARGET_X86)
+                opRegImm(cUnit, kOpAdd, rSP, (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
+#else
+                opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
+#endif
                 break;
             default:
                 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
diff --git a/src/thread.cc b/src/thread.cc
index 3892c23..24697ce 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -387,18 +387,48 @@
                      __FUNCTION__);
   stack_begin_ = reinterpret_cast<byte*>(temp_stack_base);
 
+  CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__);
+
+  // TODO: include this in the thread dumps; potentially useful in SIGQUIT output?
+  VLOG(threads) << "Native stack is at " << temp_stack_base << " (" << PrettySize(stack_size_) << ")";
+
   if (stack_size_ <= kStackOverflowReservedBytes) {
     LOG(FATAL) << "Attempt to attach a thread with a too-small stack (" << stack_size_ << " bytes)";
   }
 
+  // If we're the main thread, check whether we were run with an unlimited stack. In that case,
+  // glibc will have reported a 2GB stack for our 32-bit process, and our stack overflow detection
+  // will be broken because we'll die long before we get close to 2GB.
+  if (thin_lock_id_ == 1) {
+    rlimit stack_limit;
+    if (getrlimit(RLIMIT_STACK, &stack_limit) == -1) {
+      PLOG(FATAL) << "getrlimit(RLIMIT_STACK) failed";
+    }
+    if (stack_limit.rlim_cur == RLIM_INFINITY) {
+      // Find the default stack size for new threads...
+      pthread_attr_t default_attributes;
+      size_t default_stack_size;
+      CHECK_PTHREAD_CALL(pthread_attr_init, (&default_attributes), "default stack size query");
+      CHECK_PTHREAD_CALL(pthread_attr_getstacksize, (&default_attributes, &default_stack_size),
+                         "default stack size query");
+      CHECK_PTHREAD_CALL(pthread_attr_destroy, (&default_attributes), "default stack size query");
+
+      // ...and use that as our limit.
+      size_t old_stack_size = stack_size_;
+      stack_size_ = default_stack_size;
+      stack_begin_ += (old_stack_size - stack_size_);
+      LOG(WARNING) << "Limiting unlimited stack (reported as " << PrettySize(old_stack_size) << ");"
+                   << " to " << PrettySize(stack_size_)
+                   << " with base " << reinterpret_cast<void*>(stack_begin_);
+    }
+  }
+
   // Set stack_end_ to the bottom of the stack saving space of stack overflows
   ResetDefaultStackEnd();
 
   // Sanity check.
   int stack_variable;
   CHECK_GT(&stack_variable, reinterpret_cast<void*>(stack_end_));
-
-  CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__);
 #endif
 }