Fail-Fast on Redundant Callback Invokes

Reviewed By: javache

Differential Revision: D4295268

fbshipit-source-id: 1258ffbc02bcf7d7199348c7df8fcd744bb9963f
This commit is contained in:
Theo Yaung 2016-12-08 13:31:52 -08:00 committed by Facebook Github Bot
parent 9dcea13795
commit 4a6f2ec44a
1 changed files with 28 additions and 5 deletions

View File

@ -102,6 +102,17 @@ static RCTNullability RCTParseNullabilityPostfix(const char **input)
return RCTNullabilityUnspecified; return RCTNullabilityUnspecified;
} }
// returns YES if execution is safe to proceed (enqueue callback invocation), NO if callback has already been invoked
static BOOL RCTCheckCallbackMultipleInvocations(BOOL *didInvoke) {
if (*didInvoke) {
RCTFatal(RCTErrorWithMessage(@"Illegal callback invocation from native module. This callback type only permits a single invocation from native code."));
return NO;
} else {
*didInvoke = YES;
return YES;
}
}
SEL RCTParseMethodSignature(NSString *, NSArray<RCTMethodArgument *> **); SEL RCTParseMethodSignature(NSString *, NSArray<RCTMethodArgument *> **);
SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument *> **arguments) SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument *> **arguments)
{ {
@ -205,8 +216,11 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
return NO; return NO;
} }
__block BOOL didInvoke = NO;
RCT_BLOCK_ARGUMENT(^(NSArray *args) { RCT_BLOCK_ARGUMENT(^(NSArray *args) {
[bridge enqueueCallback:json args:args]; if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
[bridge enqueueCallback:json args:args];
}
}); });
) )
}; };
@ -302,8 +316,11 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
return NO; return NO;
} }
__block BOOL didInvoke = NO;
RCT_BLOCK_ARGUMENT(^(NSError *error) { RCT_BLOCK_ARGUMENT(^(NSError *error) {
[bridge enqueueCallback:json args:@[RCTJSErrorFromNSError(error)]]; if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
[bridge enqueueCallback:json args:@[RCTJSErrorFromNSError(error)]];
}
}); });
) )
} else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) { } else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
@ -316,8 +333,11 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
return NO; return NO;
} }
__block BOOL didInvoke = NO;
RCT_BLOCK_ARGUMENT(^(id result) { RCT_BLOCK_ARGUMENT(^(id result) {
[bridge enqueueCallback:json args:result ? @[result] : @[]]; if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
[bridge enqueueCallback:json args:result ? @[result] : @[]];
}
}); });
) )
} else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) { } else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
@ -330,9 +350,12 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
return NO; return NO;
} }
__block BOOL didInvoke = NO;
RCT_BLOCK_ARGUMENT(^(NSString *code, NSString *message, NSError *error) { RCT_BLOCK_ARGUMENT(^(NSString *code, NSString *message, NSError *error) {
NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error); if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
[bridge enqueueCallback:json args:@[errorJSON]]; NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
[bridge enqueueCallback:json args:@[errorJSON]];
}
}); });
) )
} else { } else {