Reland "v8::TryCatch now works correctly with ASAN's UseAfterReturn mode enabled."
authorishell@chromium.org <ishell@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 20 May 2014 10:13:46 +0000 (10:13 +0000)
committerishell@chromium.org <ishell@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 20 May 2014 10:13:46 +0000 (10:13 +0000)
BUG=chromium:369962
LOG=N
R=jkummerow@chromium.org

Review URL: https://codereview.chromium.org/282783004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21382 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
src/arm/simulator-arm.h
src/arm64/simulator-arm64.h
src/base/macros.h
src/ia32/simulator-ia32.h
src/isolate.cc
src/isolate.h
src/mips/simulator-mips.h
src/x64/simulator-x64.h
src/zone.h

index 94b7fa1500a6fd3f340d4f5cfbb389cdd5475506..8c2aaf9ca6c3b778901831fdfa2dd7f90b2dfe77 100644 (file)
@@ -5076,6 +5076,22 @@ class V8_EXPORT TryCatch {
    */
   void SetCaptureMessage(bool value);
 
+  /**
+   * There are cases when the raw address of C++ TryCatch object cannot be
+   * used for comparisons with addresses into the JS stack. The cases are:
+   * 1) ARM, ARM64 and MIPS simulators which have separate JS stack.
+   * 2) Address sanitizer allocates local C++ object in the heap when
+   *    UseAfterReturn mode is enabled.
+   * This method returns address that can be used for comparisons with
+   * addresses into the JS stack. When neither simulator nor ASAN's
+   * UseAfterReturn is enabled, then the address returned will be the address
+   * of the C++ try catch handler itself.
+   */
+  static void* JSStackComparableAddress(v8::TryCatch* handler) {
+    if (handler == NULL) return NULL;
+    return handler->js_stack_comparable_address_;
+  }
+
  private:
   // Make it hard to create heap-allocated TryCatch blocks.
   TryCatch(const TryCatch&);
@@ -5084,10 +5100,11 @@ class V8_EXPORT TryCatch {
   void operator delete(void*, size_t);
 
   v8::internal::Isolate* isolate_;
-  void* next_;
+  v8::TryCatch* next_;
   void* exception_;
   void* message_obj_;
   void* message_script_;
+  void* js_stack_comparable_address_;
   int message_start_pos_;
   int message_end_pos_;
   bool is_verbose_ : 1;
index 4b305b002d2ab472168431e36da16b6901746bf1..be2ac096d4684c817ca2d9ed541d1b81a86ca79e 100644 (file)
@@ -6,6 +6,9 @@
 
 #include <string.h>  // For memcpy, strlen.
 #include <cmath>  // For isnan.
+#ifdef V8_USE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif  // V8_USE_ADDRESS_SANITIZER
 #include "../include/v8-debug.h"
 #include "../include/v8-profiler.h"
 #include "../include/v8-testing.h"
@@ -37,6 +40,7 @@
 #include "runtime.h"
 #include "runtime-profiler.h"
 #include "scanner-character-streams.h"
+#include "simulator.h"
 #include "snapshot.h"
 #include "unicode-inl.h"
 #include "utils/random-number-generator.h"
@@ -1785,13 +1789,26 @@ Local<Script> Script::Compile(v8::Handle<String> source,
 
 v8::TryCatch::TryCatch()
     : isolate_(i::Isolate::Current()),
-      next_(isolate_->try_catch_handler_address()),
+      next_(isolate_->try_catch_handler()),
       is_verbose_(false),
       can_continue_(true),
       capture_message_(true),
       rethrow_(false),
       has_terminated_(false) {
   Reset();
+  js_stack_comparable_address_ = this;
+#ifdef V8_USE_ADDRESS_SANITIZER
+  void* asan_fake_stack_handle = __asan_get_current_fake_stack();
+  if (asan_fake_stack_handle != NULL) {
+    js_stack_comparable_address_ = __asan_addr_is_in_fake_stack(
+        asan_fake_stack_handle, js_stack_comparable_address_, NULL, NULL);
+    CHECK(js_stack_comparable_address_ != NULL);
+  }
+#endif
+  // Special handling for simulators which have a separate JS stack.
+  js_stack_comparable_address_ = reinterpret_cast<void*>(
+      v8::internal::SimulatorStack::RegisterCTryCatch(
+          reinterpret_cast<uintptr_t>(js_stack_comparable_address_)));
   isolate_->RegisterTryCatchHandler(this);
 }
 
@@ -1811,10 +1828,12 @@ v8::TryCatch::~TryCatch() {
       isolate_->RestorePendingMessageFromTryCatch(this);
     }
     isolate_->UnregisterTryCatchHandler(this);
+    v8::internal::SimulatorStack::UnregisterCTryCatch();
     reinterpret_cast<Isolate*>(isolate_)->ThrowException(exc);
     ASSERT(!isolate_->thread_local_top()->rethrowing_message_);
   } else {
     isolate_->UnregisterTryCatchHandler(this);
+    v8::internal::SimulatorStack::UnregisterCTryCatch();
   }
 }
 
index 9ae02c3e8d39b52351979f37782b51f68e0b9689..d55cca84a1e07c49bc8a8db323a62ab49e0a8da5 100644 (file)
@@ -37,9 +37,6 @@ typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*,
   (FUNCTION_CAST<arm_regexp_matcher>(entry)(                              \
       p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
-  reinterpret_cast<TryCatch*>(try_catch_address)
-
 // The stack limit beyond which we will throw stack overflow errors in
 // generated code. Because generated code on arm uses the C stack, we
 // just use the C stack limit.
@@ -436,10 +433,6 @@ class Simulator {
   Simulator::current(Isolate::Current())->Call( \
       entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
-  try_catch_address == NULL ?                                                  \
-      NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
-
 
 // The simulator has its own stack. Thus it has a different stack limit from
 // the C-based native code.  Setting the c_limit to indicate a very small
index 9dd353a52a9bd8a93d3ac9cfb6fc1aba418873e6..29a6583ffd7ede78bb4b1c65bb9bc6c0e11ed569 100644 (file)
@@ -54,9 +54,6 @@ typedef int (*arm64_regexp_matcher)(String* input,
   (FUNCTION_CAST<arm64_regexp_matcher>(entry)(                                \
       p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8))
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
-  reinterpret_cast<TryCatch*>(try_catch_address)
-
 // Running without a simulator there is nothing to do.
 class SimulatorStack : public v8::internal::AllStatic {
  public:
@@ -857,10 +854,6 @@ class Simulator : public DecoderVisitor {
       entry,                                                                   \
       p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8)
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
-  try_catch_address == NULL ?                                                  \
-      NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
-
 
 // The simulator has its own stack. Thus it has a different stack limit from
 // the C-based native code.
index b99f01b230c52db6c11e90a49c608919ae6ccfab..fa522fb94531c26f4eb7e95b0b3ed910ea43ad93 100644 (file)
 #define MUST_USE_RESULT V8_WARN_UNUSED_RESULT
 
 
-// Define DISABLE_ASAN macros.
+// Define V8_USE_ADDRESS_SANITIZER macros.
 #if defined(__has_feature)
 #if __has_feature(address_sanitizer)
-#define DISABLE_ASAN __attribute__((no_sanitize_address))
+#define V8_USE_ADDRESS_SANITIZER 1
 #endif
 #endif
 
-
-#ifndef DISABLE_ASAN
+// Define DISABLE_ASAN macros.
+#ifdef V8_USE_ADDRESS_SANITIZER
+#define DISABLE_ASAN __attribute__((no_sanitize_address))
+#else
 #define DISABLE_ASAN
 #endif
 
index 10356284ec66f43ef98c3505723cdee8a75a35f4..55e184cfd5a9be7add631a0aff699ae3db4b3625 100644 (file)
@@ -25,9 +25,6 @@ typedef int (*regexp_matcher)(String*, int, const byte*,
   (FUNCTION_CAST<regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7, p8))
 
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
-  (reinterpret_cast<TryCatch*>(try_catch_address))
-
 // The stack limit beyond which we will throw stack overflow errors in
 // generated code. Because generated code on ia32 uses the C stack, we
 // just use the C stack limit.
index c90bff91659be10c55cea5804fa7d6221c5fc7aa..f7605d8d21b346e85a78c557aca0b74d78cb624c 100644 (file)
@@ -69,7 +69,7 @@ void ThreadLocalTop::InitializeInternal() {
   js_entry_sp_ = NULL;
   external_callback_scope_ = NULL;
   current_vm_state_ = EXTERNAL;
-  try_catch_handler_address_ = NULL;
+  try_catch_handler_ = NULL;
   context_ = NULL;
   thread_id_ = ThreadId::Invalid();
   external_caught_exception_ = false;
@@ -98,11 +98,6 @@ void ThreadLocalTop::Initialize() {
 }
 
 
-v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
-  return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
-}
-
-
 Thread::LocalStorageKey Isolate::isolate_key_;
 Thread::LocalStorageKey Isolate::thread_id_key_;
 Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
@@ -209,9 +204,9 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
   v->VisitPointer(BitCast<Object**>(&(thread->context_)));
   v->VisitPointer(&thread->scheduled_exception_);
 
-  for (v8::TryCatch* block = thread->TryCatchHandler();
+  for (v8::TryCatch* block = thread->try_catch_handler();
        block != NULL;
-       block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
+       block = block->next_) {
     v->VisitPointer(BitCast<Object**>(&(block->exception_)));
     v->VisitPointer(BitCast<Object**>(&(block->message_obj_)));
     v->VisitPointer(BitCast<Object**>(&(block->message_script_)));
@@ -266,23 +261,14 @@ bool Isolate::IsDeferredHandle(Object** handle) {
 
 
 void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
-  // The ARM simulator has a separate JS stack.  We therefore register
-  // the C++ try catch handler with the simulator and get back an
-  // address that can be used for comparisons with addresses into the
-  // JS stack.  When running without the simulator, the address
-  // returned will be the address of the C++ try catch handler itself.
-  Address address = reinterpret_cast<Address>(
-      SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
-  thread_local_top()->set_try_catch_handler_address(address);
+  thread_local_top()->set_try_catch_handler(that);
 }
 
 
 void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
-  ASSERT(thread_local_top()->TryCatchHandler() == that);
-  thread_local_top()->set_try_catch_handler_address(
-      reinterpret_cast<Address>(that->next_));
+  ASSERT(thread_local_top()->try_catch_handler() == that);
+  thread_local_top()->set_try_catch_handler(that->next_);
   thread_local_top()->catcher_ = NULL;
-  SimulatorStack::UnregisterCTryCatch();
 }
 
 
index 1e955a92c6a275a41a65c6fb52a3227ce2a7b1ad..3a675106439881b854363a2275ecac145383cd77 100644 (file)
@@ -213,10 +213,10 @@ class ThreadLocalTop BASE_EMBEDDED {
 
   // Get the top C++ try catch handler or NULL if none are registered.
   //
-  // This method is not guarenteed to return an address that can be
+  // This method is not guaranteed to return an address that can be
   // used for comparison with addresses into the JS stack.  If such an
   // address is needed, use try_catch_handler_address.
-  v8::TryCatch* TryCatchHandler();
+  FIELD_ACCESSOR(v8::TryCatch*, try_catch_handler)
 
   // Get the address of the top C++ try catch handler or NULL if
   // none are registered.
@@ -228,12 +228,15 @@ class ThreadLocalTop BASE_EMBEDDED {
   // stack, try_catch_handler_address returns a JS stack address that
   // corresponds to the place on the JS stack where the C++ handler
   // would have been if the stack were not separate.
-  FIELD_ACCESSOR(Address, try_catch_handler_address)
+  Address try_catch_handler_address() {
+    return reinterpret_cast<Address>(
+        v8::TryCatch::JSStackComparableAddress(try_catch_handler()));
+  }
 
   void Free() {
     ASSERT(!has_pending_message_);
     ASSERT(!external_caught_exception_);
-    ASSERT(try_catch_handler_address_ == NULL);
+    ASSERT(try_catch_handler_ == NULL);
   }
 
   Isolate* isolate_;
@@ -281,7 +284,7 @@ class ThreadLocalTop BASE_EMBEDDED {
  private:
   void InitializeInternal();
 
-  Address try_catch_handler_address_;
+  v8::TryCatch* try_catch_handler_;
 };
 
 
@@ -559,7 +562,7 @@ class Isolate {
     thread_local_top_.pending_message_script_ = heap_.the_hole_value();
   }
   v8::TryCatch* try_catch_handler() {
-    return thread_local_top_.TryCatchHandler();
+    return thread_local_top_.try_catch_handler();
   }
   Address try_catch_handler_address() {
     return thread_local_top_.try_catch_handler_address();
index feeb7bcfc159067f3ae7f50f78958d2fe37a52bd..668297f93452022bbac9576cd38d02e0f253a658 100644 (file)
@@ -38,9 +38,6 @@ typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
   (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
       p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
-  reinterpret_cast<TryCatch*>(try_catch_address)
-
 // The stack limit beyond which we will throw stack overflow errors in
 // generated code. Because generated code on mips uses the C stack, we
 // just use the C stack limit.
@@ -390,10 +387,6 @@ class Simulator {
     Simulator::current(Isolate::Current())->Call( \
         entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
-  try_catch_address == NULL ?                                                  \
-      NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
-
 
 // The simulator has its own stack. Thus it has a different stack limit from
 // the C-based native code.  Setting the c_limit to indicate a very small
index a43728f01dcc2cf04147c41ca75ca95c05149d04..3e5597412a875c63d6c94505b6aed46d93967bc0 100644 (file)
@@ -24,9 +24,6 @@ typedef int (*regexp_matcher)(String*, int, const byte*,
 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
   (FUNCTION_CAST<regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7, p8))
 
-#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
-  (reinterpret_cast<TryCatch*>(try_catch_address))
-
 // The stack limit beyond which we will throw stack overflow errors in
 // generated code. Because generated code on x64 uses the C stack, we
 // just use the C stack limit.
index 573e13e1d4af82fb89e41b90135865071285f8d7..d3a1b578ac1b44e3b5f3d17562d58e23cb2efead 100644 (file)
 namespace v8 {
 namespace internal {
 
-#if defined(__has_feature)
-  #if __has_feature(address_sanitizer)
-    #define V8_USE_ADDRESS_SANITIZER
-  #endif
-#endif
 
 class Segment;
 class Isolate;