Reland "v8::TryCatch now works correctly with ASAN's UseAfterReturn mode enabled."
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
This commit is contained in:
parent
2c6438bbfa
commit
2a62cce170
19
include/v8.h
19
include/v8.h
@ -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;
|
||||
|
21
src/api.cc
21
src/api.cc
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -54,15 +54,17 @@
|
||||
#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 V8_USE_ADDRESS_SANITIZER 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Define DISABLE_ASAN macros.
|
||||
#ifdef V8_USE_ADDRESS_SANITIZER
|
||||
#define DISABLE_ASAN __attribute__((no_sanitize_address))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DISABLE_ASAN
|
||||
#else
|
||||
#define DISABLE_ASAN
|
||||
#endif
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -15,11 +15,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define V8_USE_ADDRESS_SANITIZER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Segment;
|
||||
class Isolate;
|
||||
|
Loading…
Reference in New Issue
Block a user