-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crash for web socket in some race conditions #22439
Conversation
Generated by 🚫 dangerJS |
Thanks for opening this new PR :) |
This PR unfortunately doesn't come with a reproducible test plan of the before/after behavior and the change itself is quite large without any form of automated testing. In order to land this, would you mind working both on the test plan and possibly adding some form of tests? |
@cpojer Emm, I did try to find a way to test it, but I have no idea currently, because it's a race condition, |
[In environment Xcode10.1 react-native:0.55.4 react:16.3.1 ,I have modified RCTSRWebSocket.m and still crashes,What is the cause? @zhongwuzw |
I can confirm that I'm also seeing this crash in my app. No idea how to repro though.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great overall, thanks for working on this. This code is pretty tricky so we need to be careful.
@cpojer The changes are actually less scary than I though, mostly just whitespace.
Were you able to test this in production to make sure the crash does not happen and that there are no regressions?
|
||
// Cleanup NSStream's delegate in the same RunLoop used by the streams themselves: | ||
// This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc | ||
NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why you can't use dispatch_async
to schedule cleanup here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janicduplessis Emm, we need to schedule cleanup on RCTSR_networkRunLoop
, seems we have no dispatch_queue
here. Maybe we can use performSelector
, but we can keep use timer, because they are the same actually.
Libraries/WebSocket/RCTSRWebSocket.m
Outdated
assert(_workQueue != NULL); | ||
|
||
// _workQueue cannot be NULL | ||
if (!_workQueue) { return; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If work queue cannot be null can we just remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janicduplessis In theory, we don't need to check work queue nullable, the reason I add this is to add the further safe check, because if work queue is null, it would crash immediately.
- (void)_cleanupSelfReference:(NSTimer *)timer | ||
{ | ||
// Remove the streams, right now, from the networkRunLoop | ||
[_inputStream close]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check the stream status here before trying to close it like we do here https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTSRWebSocket.m#L1034
Might be worth extracting to a shared method to safely close streams.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@janicduplessis 👍 We can extract it to a separate method.
@janicduplessis we have been using this patch in our prod app for months now (more or less) and it's working super well for us. And yes I don't have a way to repro either, it's a weird prod edge case. |
Emm, seems it's the apple's internal bug? maybe it's not related to this issue? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
@zhongwuzw merged commit dd209bb into |
Summary: Fixes facebook#21086. Fixes facebook#6117. This PR fixes a crash caused by a race condition when `webSocket` deallocated and `NSStream` delegate callback, because `NSStream`'s delegate callback be called on `RCTSR_networkRunLoop`. This PR mainly changes: * Remove unnecessary `nil` operation in `dealloc` method. * Add a new method `_scheduleCleanUp` to schedule `webSocket` cleanup also on `RCTSR_networkRunLoop`. * In `stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode` delegate method, add a `wself` to make safe further. Pull Request resolved: facebook#22439 Differential Revision: D13564247 Pulled By: cpojer fbshipit-source-id: 675c1b2805aa45c54d7708d796f5843ef7ea34e2
Summary: Fixes facebook#21086. Fixes facebook#6117. This PR fixes a crash caused by a race condition when `webSocket` deallocated and `NSStream` delegate callback, because `NSStream`'s delegate callback be called on `RCTSR_networkRunLoop`. This PR mainly changes: * Remove unnecessary `nil` operation in `dealloc` method. * Add a new method `_scheduleCleanUp` to schedule `webSocket` cleanup also on `RCTSR_networkRunLoop`. * In `stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode` delegate method, add a `wself` to make safe further. Pull Request resolved: facebook#22439 Differential Revision: D13564247 Pulled By: cpojer fbshipit-source-id: 675c1b2805aa45c54d7708d796f5843ef7ea34e2
Summary: Fixes #21086. Fixes #6117. This PR fixes a crash caused by a race condition when `webSocket` deallocated and `NSStream` delegate callback, because `NSStream`'s delegate callback be called on `RCTSR_networkRunLoop`. This PR mainly changes: * Remove unnecessary `nil` operation in `dealloc` method. * Add a new method `_scheduleCleanUp` to schedule `webSocket` cleanup also on `RCTSR_networkRunLoop`. * In `stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode` delegate method, add a `wself` to make safe further. Pull Request resolved: #22439 Differential Revision: D13564247 Pulled By: cpojer fbshipit-source-id: 675c1b2805aa45c54d7708d796f5843ef7ea34e2
Summary: Fixes #21086. Fixes #6117. This PR fixes a crash caused by a race condition when `webSocket` deallocated and `NSStream` delegate callback, because `NSStream`'s delegate callback be called on `RCTSR_networkRunLoop`. This PR mainly changes: * Remove unnecessary `nil` operation in `dealloc` method. * Add a new method `_scheduleCleanUp` to schedule `webSocket` cleanup also on `RCTSR_networkRunLoop`. * In `stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode` delegate method, add a `wself` to make safe further. Pull Request resolved: facebook/react-native#22439 Differential Revision: D13564247 Pulled By: cpojer fbshipit-source-id: 675c1b2805aa45c54d7708d796f5843ef7ea34e2
Summary: Fixes facebook#21086. Fixes facebook#6117. This PR fixes a crash caused by a race condition when `webSocket` deallocated and `NSStream` delegate callback, because `NSStream`'s delegate callback be called on `RCTSR_networkRunLoop`. This PR mainly changes: * Remove unnecessary `nil` operation in `dealloc` method. * Add a new method `_scheduleCleanUp` to schedule `webSocket` cleanup also on `RCTSR_networkRunLoop`. * In `stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode` delegate method, add a `wself` to make safe further. Pull Request resolved: facebook#22439 Differential Revision: D13564247 Pulled By: cpojer fbshipit-source-id: 675c1b2805aa45c54d7708d796f5843ef7ea34e2
Fixes #21086.
Fixes #6117.
This PR fixes a crash caused by a race condition when
webSocket
deallocated andNSStream
delegate callback, becauseNSStream
's delegate callback be called onRCTSR_networkRunLoop
.This PR mainly changes:
nil
operation indealloc
method._scheduleCleanUp
to schedulewebSocket
cleanup also onRCTSR_networkRunLoop
.stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
delegate method, add awself
to make safe further.Test Plan:
Reproduce steps:
Run any
react-native
project, and keep it running, it would crash at some point.Changelog:
[iOS] [BUGFIX] [RCTSRWebSocket] - Fix crash for web socket in some race conditions.