Skip to content

Commit

Permalink
Fixed fuzzer app and ensured that React does not crash when fuzzed
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Aug 12, 2015
1 parent 3923000 commit a86e6b7
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 22 deletions.
7 changes: 5 additions & 2 deletions Libraries/Utilities/MessageQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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';
Expand All @@ -245,6 +246,8 @@ class MessageQueue {
return self.__nativeCall(module, method, args, onFail, onSucc);
};
}
fn.type = type;
return fn;
}

}
Expand Down
26 changes: 14 additions & 12 deletions React/Base/RCTModuleMethod.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#import "RCTLog.h"
#import "RCTUtils.h"

typedef void (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);

@implementation RCTMethodArgument

Expand Down Expand Up @@ -166,6 +166,7 @@ - (void)processMethodSignature
[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSUInteger index, id json) { \
_logic \
[invocation setArgument:&value atIndex:(index) + 2]; \
return YES; \
}];

__weak RCTModuleMethod *weakSelf = self;
Expand All @@ -174,7 +175,7 @@ - (void)processMethodSignature

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
Expand Down Expand Up @@ -268,13 +269,13 @@ - (void)processMethodSignature

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) {});
)
Expand All @@ -285,7 +286,7 @@ - (void)processMethodSignature
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
Expand All @@ -302,7 +303,7 @@ - (void)processMethodSignature
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
Expand Down Expand Up @@ -350,12 +351,11 @@ - (void)processMethodSignature
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);
}
};
}
Expand Down Expand Up @@ -408,9 +408,11 @@ - (void)invokeWithBridge:(RCTBridge *)bridge
// 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++;
}

Expand Down
2 changes: 1 addition & 1 deletion React/Executors/RCTContextExecutor.m
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ - (void)injectJSONText:(NSString *)script
}), @"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);
Expand Down
12 changes: 9 additions & 3 deletions React/Modules/RCTUIManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ - (void)_manageChildren:(NSNumber *)containerReactTag
- (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) {
Expand Down Expand Up @@ -871,8 +872,13 @@ - (void)flushUIBlocks
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),
Expand Down Expand Up @@ -1043,7 +1049,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
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;
Expand Down
11 changes: 7 additions & 4 deletions React/Views/RCTWebViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ - (NSDictionary *)constantsToExport
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goBack];
}
[view goBack];
}];
}

Expand All @@ -73,8 +74,9 @@ - (NSDictionary *)constantsToExport
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goForward];
}
[view goForward];
}];
}

Expand All @@ -84,9 +86,10 @@ - (NSDictionary *)constantsToExport
[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];
}];
}

Expand Down

0 comments on commit a86e6b7

Please sign in to comment.