Guard against invalid JS bundle

Reviewed By: tadeuzagallo

Differential Revision: D2767961

fb-gh-sync-id: 4e9162ddbb2986a56dd129743e316d6e83bb8cb3
This commit is contained in:
Pieter De Baets 2015-12-17 17:26:12 -08:00 committed by facebook-github-bot-7
parent ba3a5f0eec
commit 5b4e873c68
2 changed files with 55 additions and 19 deletions

View File

@ -69,13 +69,40 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
@interface RCTAllocationTests : XCTestCase
@end
@implementation RCTAllocationTests
@implementation RCTAllocationTests {
NSURL *_bundleURL;
}
- (void)setUp
{
[super setUp];
NSString *bundleContents =
@"var __fbBatchedBridge = {"
" callFunctionReturnFlushedQueue: function() {},"
" invokeCallbackAndReturnFlushedQueue: function() {},"
" flushedQueue: function() {},"
"};";
NSURL *tempDir = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
[[NSFileManager defaultManager] createDirectoryAtURL:tempDir withIntermediateDirectories:YES attributes:nil error:NULL];
_bundleURL = [tempDir URLByAppendingPathComponent:@"rctallocationtests-bundle.js"];
[bundleContents writeToURL:_bundleURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
- (void)tearDown
{
[super tearDown];
[[NSFileManager defaultManager] removeItemAtURL:_bundleURL error:NULL];
}
- (void)testBridgeIsDeallocated
{
__weak RCTBridge *weakBridge;
@autoreleasepool {
RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:nil
RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:_bundleURL
moduleName:@""
initialProperties:nil
launchOptions:nil];
@ -91,7 +118,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
{
AllocationTestModule *module = [AllocationTestModule new];
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:^{
return @[module];
}
@ -109,11 +136,11 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
__weak AllocationTestModule *weakModule;
@autoreleasepool {
AllocationTestModule *module = [AllocationTestModule new];
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
moduleProvider:^{
return @[module];
}
launchOptions:nil];
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:^{
return @[module];
}
launchOptions:nil];
weakModule = module;
XCTAssertNotNil(weakModule, @"AllocationTestModule should have been created");
(void)bridge;
@ -140,7 +167,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
{
__weak id<RCTJavaScriptExecutor> weakExecutor;
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:nil
launchOptions:nil];
weakExecutor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
@ -156,7 +183,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
{
__weak id weakContext;
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:nil
launchOptions:nil];
id executor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
@ -171,7 +198,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
- (void)testContentViewIsInvalidated
{
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:nil
launchOptions:nil];
__weak UIView *rootContentView;
@ -190,7 +217,7 @@ RCT_EXPORT_METHOD(test:(__unused NSString *)a
RCTBridge *bridge;
__weak id batchedBridge;
@autoreleasepool {
bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:nil launchOptions:nil];
bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL moduleProvider:nil launchOptions:nil];
batchedBridge = bridge.batchedBridge;
XCTAssertTrue([batchedBridge isValid], @"RCTBatchedBridge should be valid");
[bridge reload];

View File

@ -119,8 +119,8 @@ static NSString *RCTJSValueToJSONString(JSContextRef context, JSValueRef value,
static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
{
NSString *errorMessage = jsError ? RCTJSValueToNSString(context, jsError, NULL) : @"unknown JS error";
NSString *details = jsError ? RCTJSValueToJSONString(context, jsError, NULL, 2) : @"no details";
NSString *errorMessage = jsError ? RCTJSValueToNSString(context, jsError, NULL) : @"Unknown JS error";
NSString *details = jsError ? RCTJSValueToJSONString(context, jsError, NULL, 2) : @"No details";
return [NSError errorWithDomain:@"JS" code:1 userInfo:@{NSLocalizedDescriptionKey: errorMessage, NSLocalizedFailureReasonErrorKey: details}];
}
@ -394,14 +394,12 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
JSStringRelease(moduleNameJSStringRef);
if (moduleJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, moduleJSRef)) {
// get method
JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
JSValueRef methodJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
JSStringRelease(methodNameJSStringRef);
if (methodJSRef != NULL && errorJSRef == NULL) {
if (methodJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, methodJSRef)) {
// direct method invoke with no arguments
if (arguments.count == 0) {
resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 0, NULL, &errorJSRef);
@ -433,11 +431,22 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
JSStringRelease(argsJSStringRef);
}
}
} else {
if (!errorJSRef && JSValueIsUndefined(contextJSRef, methodJSRef)) {
error = RCTErrorWithMessage([NSString stringWithFormat:@"Unable to execute JS call: method %@ is undefined", method]);
}
}
} else {
if (!errorJSRef && JSValueIsUndefined(contextJSRef, moduleJSRef)) {
error = RCTErrorWithMessage(@"Unable to execute JS call: __fbBatchedBridge is undefined");
}
}
if (errorJSRef) {
onComplete(nil, RCTNSErrorFromJSError(contextJSRef, errorJSRef));
if (errorJSRef || error) {
if (!error) {
error = RCTNSErrorFromJSError(contextJSRef, errorJSRef);
}
onComplete(nil, error);
return;
}