mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-10 22:47:58 +08:00
Check for thread consistency in JSCRuntime
Summary: In the version of JSC on iOS 11, creating a JSContext on one thread and using it on another can trigger subtle and nearly impossible to debug reentrancy-related crashes in the VM (see https://bugs.webkit.org/show_bug.cgi?id=186827). In !NDEBUG builds, check for this case and throw an exception, so it can be detected early. Reviewed By: amnn Differential Revision: D13313264 fbshipit-source-id: ee85435c20e23c8520495ce743d2f91f2eeada5c
This commit is contained in:
committed by
Facebook Github Bot
parent
512676c65e
commit
bdb084e8a8
@@ -53,6 +53,8 @@ void Instance::initializeBridge(
|
||||
m_syncCV.notify_all();
|
||||
});
|
||||
|
||||
// If the NativeToJsBridge ctor throws an exception, this check will
|
||||
// likely happen before before the redbox can be rendered.
|
||||
CHECK(nativeToJsBridge_);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,14 @@ struct Lock {
|
||||
void unlock(const jsc::JSCRuntime&) const {}
|
||||
};
|
||||
|
||||
#if __has_builtin(__builtin_expect)
|
||||
#define JSC_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
|
||||
#define JSC_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
|
||||
#else
|
||||
#define JSC_LIKELY(EXPR) (EXPR)
|
||||
#define JSC_UNLIKELY(EXPR) (EXPR)
|
||||
#endif
|
||||
|
||||
class JSCRuntime : public jsi::Runtime {
|
||||
public:
|
||||
// Creates new context in new context group
|
||||
@@ -191,23 +199,32 @@ class JSCRuntime : public jsi::Runtime {
|
||||
void checkException(JSValueRef exc, const char* msg);
|
||||
void checkException(JSValueRef res, JSValueRef exc, const char* msg);
|
||||
|
||||
void checkThreadId() {
|
||||
#ifndef NDEBUG
|
||||
if (JSC_UNLIKELY(tid_ != std::this_thread::get_id())) {
|
||||
// In the version of JSC on iOS 11, creating a JSContext on one
|
||||
// thread and using it on another can trigger subtle and nearly
|
||||
// impossible to debug reentrancy-related crashes in the VM (see
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=186827). In !NDEBUG
|
||||
// builds, check for this case and throw an exception, so it can
|
||||
// be detected early. This could be called anywhere, but for
|
||||
// now, it's called only in a few less frequently used places to
|
||||
// avoid unnecessary checks.
|
||||
throw std::logic_error("Detected JSC thread hazard");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JSGlobalContextRef ctx_;
|
||||
std::atomic<bool> ctxInvalid_;
|
||||
std::string desc_;
|
||||
#ifndef NDEBUG
|
||||
mutable std::atomic<intptr_t> objectCounter_;
|
||||
mutable std::atomic<intptr_t> stringCounter_;
|
||||
std::thread::id tid_;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if __has_builtin(__builtin_expect)
|
||||
#define JSC_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
|
||||
#define JSC_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
|
||||
#else
|
||||
#define JSC_LIKELY(EXPR) (EXPR)
|
||||
#define JSC_UNLIKELY(EXPR) (EXPR)
|
||||
#endif
|
||||
|
||||
#define JSC_ASSERT(x) \
|
||||
do { \
|
||||
if (JSC_UNLIKELY(!!(x))) { \
|
||||
@@ -292,7 +309,8 @@ JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
|
||||
#ifndef NDEBUG
|
||||
,
|
||||
objectCounter_(0),
|
||||
stringCounter_(0)
|
||||
stringCounter_(0),
|
||||
tid_(std::this_thread::get_id())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
@@ -317,6 +335,8 @@ JSCRuntime::~JSCRuntime() {
|
||||
void JSCRuntime::evaluateJavaScript(
|
||||
std::unique_ptr<const jsi::Buffer> buffer,
|
||||
const std::string& sourceURL) {
|
||||
checkThreadId();
|
||||
|
||||
std::string tmp(
|
||||
reinterpret_cast<const char*>(buffer->data()), buffer->size());
|
||||
JSStringRef sourceRef = JSStringCreateWithUTF8CString(tmp.c_str());
|
||||
@@ -335,6 +355,8 @@ void JSCRuntime::evaluateJavaScript(
|
||||
}
|
||||
|
||||
jsi::Object JSCRuntime::global() {
|
||||
checkThreadId();
|
||||
|
||||
return createObject(JSContextGetGlobalObject(ctx_));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user