From c5004d5dd087d851fce0e77f2c0496ab8496ccd0 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 22 Jun 2017 08:17:03 -0700 Subject: [PATCH] Make startup errors in the websocket executor invalidate the bridge Reviewed By: mhorowitz Differential Revision: D5226936 fbshipit-source-id: b6d605974674d0e6f86559f2583553e3636d389b --- Libraries/WebSocket/RCTWebSocketExecutor.m | 8 ++++++++ React/CxxBridge/RCTCxxBridge.mm | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m index 06217d886..ecb0b260c 100644 --- a/Libraries/WebSocket/RCTWebSocketExecutor.m +++ b/Libraries/WebSocket/RCTWebSocketExecutor.m @@ -172,6 +172,11 @@ RCT_EXPORT_MODULE() - (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)URL onComplete:(RCTJavaScriptCompleteBlock)onComplete { + // Hack: the bridge transitions out of loading state as soon as this method returns, which prevents us + // from completely invalidating the bridge and preventing an endless barage of RCTLog.logIfNoNativeHook + // calls if the JS execution environment is broken. We therefore block this thread until this message has returned. + dispatch_semaphore_t scriptSem = dispatch_semaphore_create(0); + NSDictionary *message = @{ @"method": @"executeApplicationScript", @"url": RCTNullIfNil(URL.absoluteString), @@ -184,7 +189,10 @@ RCT_EXPORT_MODULE() NSString *error = reply[@"error"]; onComplete(error ? RCTErrorWithMessage(error) : nil); } + dispatch_semaphore_signal(scriptSem); }]; + + dispatch_semaphore_wait(scriptSem, DISPATCH_TIME_FOREVER); } - (void)flushedQueue:(RCTJavaScriptCallback)onComplete diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index b458854ec..79abfd440 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -1010,7 +1010,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR // ensureOnJavaScriptThread may execute immediately, so use jsMessageThread, to make sure // the block is invoked after callJSFunction if (completion) { - self->_jsMessageThread->runOnQueue(completion); + if (self->_jsMessageThread) { + self->_jsMessageThread->runOnQueue(completion); + } else { + RCTLogWarn(@"Can't invoke completion without messageThread"); + } } } }];