Fixed fuzzer app and ensured that React does not crash when fuzzed

This commit is contained in:
Nick Lockwood
2015-08-11 19:18:08 -01:00
parent 39230000de
commit a86e6b76fb
5 changed files with 36 additions and 22 deletions

View File

@@ -218,9 +218,10 @@ class MessageQueue {
return null;
}
let fn = null;
let self = this;
if (type === MethodTypes.remoteAsync) {
return function(...args) {
fn = function(...args) {
return new Promise((resolve, reject) => {
self.__nativeCall(module, method, args, resolve, (errorData) => {
var error = createErrorFromErrorData(errorData);
@@ -229,7 +230,7 @@ class MessageQueue {
});
};
} else {
return function(...args) {
fn = function(...args) {
let lastArg = args.length > 0 ? args[args.length - 1] : null;
let secondLastArg = args.length > 1 ? args[args.length - 2] : null;
let hasSuccCB = typeof lastArg === 'function';
@@ -245,6 +246,8 @@ class MessageQueue {
return self.__nativeCall(module, method, args, onFail, onSucc);
};
}
fn.type = type;
return fn;
}
}

View File

@@ -17,7 +17,7 @@
#import "RCTLog.h"
#import "RCTUtils.h"
typedef void (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
@implementation RCTMethodArgument
@@ -166,6 +166,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSUInteger index, id json) { \
_logic \
[invocation setArgument:&value atIndex:(index) + 2]; \
return YES; \
}];
__weak RCTModuleMethod *weakSelf = self;
@@ -174,7 +175,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
if (RCT_DEBUG && json && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a function");
return;
return NO;
}
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
@@ -268,13 +269,13 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
if (RCT_DEBUG && json && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a function");
return;
return NO;
}
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
__autoreleasing id value = (json ? ^(NSError *error) {
[bridge _invokeAndProcessModule:@"BatchedBridge"
method:@"invokeCallbackAndReturnFlushedQueue"
method:@"invokeCallbackAndReturnFlushedQueue"
arguments:@[json, @[RCTJSErrorFromNSError(error)]]];
} : ^(__unused NSError *error) {});
)
@@ -285,7 +286,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a promise resolver function");
return;
return NO;
}
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
@@ -302,7 +303,7 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogArgumentError(weakSelf, index, json, "should be a promise rejecter function");
return;
return NO;
}
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
@@ -350,12 +351,11 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
if (nullability == RCTNonnullable) {
RCTArgumentBlock oldBlock = argumentBlocks[i - 2];
argumentBlocks[i - 2] = ^(RCTBridge *bridge, NSUInteger index, id json) {
if (json == nil || json == (id)kCFNull) {
if (json == nil) {
RCTLogArgumentError(weakSelf, index, typeName, "must not be null");
id null = nil;
[invocation setArgument:&null atIndex:index + 2];
return NO;
} else {
oldBlock(bridge, index, json);
return oldBlock(bridge, index, json);
}
};
}
@@ -408,9 +408,11 @@ void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **arguments)
// Set arguments
NSUInteger index = 0;
for (id json in arguments) {
id arg = RCTNilIfNull(json);
RCTArgumentBlock block = _argumentBlocks[index];
block(bridge, index, arg);
if (!block(bridge, index, RCTNilIfNull(json))) {
// Invalid argument, abort
return;
}
index++;
}

View File

@@ -558,7 +558,7 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
}), @"js_call,json_call", (@{@"objectName": objectName}))];
}
RCT_EXPORT_METHOD(setContextName:(NSString *)name)
RCT_EXPORT_METHOD(setContextName:(nonnull NSString *)name)
{
if (JSGlobalContextSetName != NULL) {
JSStringRef JSName = JSStringCreateWithCFString((__bridge CFStringRef)name);

View File

@@ -820,6 +820,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
- (void)batchDidComplete
{
RCTProfileBeginEvent();
// Gather blocks to be executed now that all view hierarchy manipulations have
// been completed (note that these may still take place before layout has finished)
for (RCTComponentData *componentData in _componentDataByName.allValues) {
@@ -871,8 +872,13 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
dispatch_async(dispatch_get_main_queue(), ^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
for (dispatch_block_t block in previousPendingUIBlocks) {
block();
@try {
for (dispatch_block_t block in previousPendingUIBlocks) {
block();
}
}
@catch (NSException *exception) {
RCTLogError(@"Exception thrown while executing UI block: %@", exception);
}
RCTProfileEndEvent(@"UIManager flushUIBlocks", @"objc_call", @{
@"count": @(previousPendingUIBlocks.count),
@@ -1043,7 +1049,7 @@ RCT_EXPORT_METHOD(setMainScrollViewTag:(nonnull NSNumber *)reactTag)
uiManager.mainScrollView = (id<RCTScrollableProtocol>)view;
uiManager.mainScrollView.nativeMainScrollDelegate = uiManager.nativeMainScrollDelegate;
} else {
RCTAssert(NO, @"Tag #%@ does not conform to RCTScrollableProtocol", reactTag);
RCTLogError(@"Tag #%@ does not conform to RCTScrollableProtocol", reactTag);
}
} else {
uiManager.mainScrollView = nil;

View File

@@ -62,8 +62,9 @@ RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag)
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goBack];
}
[view goBack];
}];
}
@@ -73,8 +74,9 @@ RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag)
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goForward];
}
[view goForward];
}];
}
@@ -84,9 +86,10 @@ RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag)
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogMustFix(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view reload];
}
[view reload];
}];
}