Skip to content

Commit

Permalink
Guard against invalid JS bundle
Browse files Browse the repository at this point in the history
Reviewed By: tadeuzagallo

Differential Revision: D2767961

fb-gh-sync-id: 4e9162ddbb2986a56dd129743e316d6e83bb8cb3
  • Loading branch information
javache authored and facebook-github-bot-7 committed Dec 18, 2015
1 parent ba3a5f0 commit 5b4e873
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 19 deletions.
51 changes: 39 additions & 12 deletions Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,40 @@ - (void)invalidate
@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];
Expand All @@ -91,7 +118,7 @@ - (void)testModulesAreInvalidated
{
AllocationTestModule *module = [AllocationTestModule new];
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:^{
return @[module];
}
Expand All @@ -109,11 +136,11 @@ - (void)testModulesAreDeallocated
__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;
Expand All @@ -140,7 +167,7 @@ - (void)testJavaScriptExecutorIsDeallocated
{
__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"];
Expand All @@ -156,7 +183,7 @@ - (void)testJavaScriptContextIsDeallocated
{
__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"];
Expand All @@ -171,7 +198,7 @@ - (void)testJavaScriptContextIsDeallocated

- (void)testContentViewIsInvalidated
{
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
moduleProvider:nil
launchOptions:nil];
__weak UIView *rootContentView;
Expand All @@ -190,7 +217,7 @@ - (void)testUnderlyingBridgeIsDeallocated
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];
Expand Down
23 changes: 16 additions & 7 deletions React/Executors/RCTJSCExecutor.m
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ @implementation RCTJSCExecutor

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}];
}

Expand Down Expand Up @@ -394,14 +394,12 @@ - (void)_executeJSCall:(NSString *)method
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);
Expand Down Expand Up @@ -433,11 +431,22 @@ - (void)_executeJSCall:(NSString *)method
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;
}

Expand Down

0 comments on commit 5b4e873

Please sign in to comment.