-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Fixed crashes due to race conditions with NSMutableDictionary
access in AFHTTPRequestSerializer
#3526
Fixed crashes due to race conditions with NSMutableDictionary
access in AFHTTPRequestSerializer
#3526
Conversation
…RequestSerialiser, added a dispatch queue for safety in multithreaded environments.
…RequestSerialiser – Added unit test which reproduces the issue. NB: as the crash is caused by using a dictionary in a way that the runtime did not expect, it typically causes intermittent crashes which are almost always in unrelated areas of the app. This seems to be strongly related to deallocation of the values in the dictionary, but this may not be the only cause. As such, there is nothing to positively test for, the test succeeds if it doesn't EXC_BAD_ACCESS when cleaning up the @autoreleasepool at the end.
…RequestSerialiser – Moved unit test to a better location.
CI tests seem to be failing either with unrelated test failures, which fail for master also on my dev machine, some intermittently, or the test runner failing. If you think that's incorrect and my change has caused a problem, do let me know! |
Thank you so much for this fix! I bet that was a nasty one to track down! 🍻 |
Yay, my first public PR! 🎉🎈🍾 Cheers |
@kcharwood can we have release with this fix ? |
I also ran into this issue recently and have been pretty perplexed by the problem, so thanks to @alexbird for tracking it down! |
Sadly I have gotten some new crashes which I believe happen because of this fix 👎 |
NSMutableDictionary
access in AFHTTPRequestSerializer
@@ -208,6 +209,7 @@ - (instancetype)init { | |||
self.stringEncoding = NSUTF8StringEncoding; | |||
|
|||
self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary]; | |||
self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT); |
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.
Shouldn't this be a SERIAL queue?
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.
Never mind, I see that dispatch_barrier_async
is used with CONCURRENT queues.
@aopod I tried to revert the
So it seems your blog post is referring to a similar but unrelated crash which also happens due to multithreaded use. The fix in this PR is more correct and fixes both issues. However, I am still observing a rare crash in |
@tmm1 I have to admit that |
Why would you use queues and synchronous dispatching over a simple call to |
@tewha Slightly higher performance. A call to I just found this thread hidden in an email folder, so have been oblivious to the conversation so far! |
Alright, I guess that makes sense. Thanks! :) I was a bit concerned it was hiding a possible deadlock to most reading the code. |
This is a fix for an intermittent crash bug which is likely to occur in any app which sets header values with dynamic values over around six characters long. These strings are reference counted, but the counting goes wrong because the owner, the headers dictionary, is not a thread-safe collection, but will be used from multiple threads in normal use of the AFNetworking library. The frequency of crashes increases greatly if you have a header which needs to be updated constantly. The crashes appear in areas of the app which are almost always completely unrelated, but often have deallocation in the stack trace.
This fix has been included in a shipping app with ~400k daily launches since the end of February, and has reduced our crash rate to almost nil.
I have included a unit test which reproduces the issue, but more as a courtesy than as a proper unit test. There is nothing to positively test for, the test succeeds if it doesn't EXC_BAD_ACCESS when cleaning up the @autoreleasepool at the end.