Skip to content

Commit 4a6f2ec

Browse files
theoyFacebook Github Bot
authored andcommitted
Fail-Fast on Redundant Callback Invokes
Reviewed By: javache Differential Revision: D4295268 fbshipit-source-id: 1258ffbc02bcf7d7199348c7df8fcd744bb9963f
1 parent 9dcea13 commit 4a6f2ec

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

React/Base/RCTModuleMethod.m

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ static RCTNullability RCTParseNullabilityPostfix(const char **input)
102102
return RCTNullabilityUnspecified;
103103
}
104104

105+
// returns YES if execution is safe to proceed (enqueue callback invocation), NO if callback has already been invoked
106+
static BOOL RCTCheckCallbackMultipleInvocations(BOOL *didInvoke) {
107+
if (*didInvoke) {
108+
RCTFatal(RCTErrorWithMessage(@"Illegal callback invocation from native module. This callback type only permits a single invocation from native code."));
109+
return NO;
110+
} else {
111+
*didInvoke = YES;
112+
return YES;
113+
}
114+
}
115+
105116
SEL RCTParseMethodSignature(NSString *, NSArray<RCTMethodArgument *> **);
106117
SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument *> **arguments)
107118
{
@@ -205,8 +216,11 @@ - (void)processMethodSignature
205216
return NO;
206217
}
207218

219+
__block BOOL didInvoke = NO;
208220
RCT_BLOCK_ARGUMENT(^(NSArray *args) {
209-
[bridge enqueueCallback:json args:args];
221+
if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
222+
[bridge enqueueCallback:json args:args];
223+
}
210224
});
211225
)
212226
};
@@ -302,8 +316,11 @@ - (void)processMethodSignature
302316
return NO;
303317
}
304318

319+
__block BOOL didInvoke = NO;
305320
RCT_BLOCK_ARGUMENT(^(NSError *error) {
306-
[bridge enqueueCallback:json args:@[RCTJSErrorFromNSError(error)]];
321+
if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
322+
[bridge enqueueCallback:json args:@[RCTJSErrorFromNSError(error)]];
323+
}
307324
});
308325
)
309326
} else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
@@ -316,8 +333,11 @@ - (void)processMethodSignature
316333
return NO;
317334
}
318335

336+
__block BOOL didInvoke = NO;
319337
RCT_BLOCK_ARGUMENT(^(id result) {
320-
[bridge enqueueCallback:json args:result ? @[result] : @[]];
338+
if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
339+
[bridge enqueueCallback:json args:result ? @[result] : @[]];
340+
}
321341
});
322342
)
323343
} else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
@@ -330,9 +350,12 @@ - (void)processMethodSignature
330350
return NO;
331351
}
332352

353+
__block BOOL didInvoke = NO;
333354
RCT_BLOCK_ARGUMENT(^(NSString *code, NSString *message, NSError *error) {
334-
NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
335-
[bridge enqueueCallback:json args:@[errorJSON]];
355+
if (RCTCheckCallbackMultipleInvocations(&didInvoke)) {
356+
NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
357+
[bridge enqueueCallback:json args:@[errorJSON]];
358+
}
336359
});
337360
)
338361
} else {

0 commit comments

Comments
 (0)