-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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 crashes caused by failing to unlock or destroy a static mutex while the app is being terminated #577
Conversation
…le the app is being terminated
@@ -46,28 +46,42 @@ @interface ASBasicImageDownloaderContext () | |||
@implementation ASBasicImageDownloaderContext | |||
|
|||
static NSMutableDictionary *currentRequests = nil; | |||
static ASDN::RecursiveMutex currentRequestsLock; | |||
static ASDN::StaticMutex currentRequestsLock = ASDISPLAYNODE_MUTEX_INITIALIZER; |
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.
Not sure why this is a recursive mutex in the first place.
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.
I hope for no good reason! Otherwise deadlocks…
@nguyenhuy thanks for the agenda and patch, very interesting. I still not understand how it triggers the assertion. Just two questions: 1 Have you reproduced it? And when do you plan next release?;) |
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.
Wow it's awesome to know what is going on here.
What do you think about changing assert
in ASDISPLAYNODE_THREAD_ASSERT_ON_ERROR
into NSCAssert
so that we won't get crashes in production? assert
is enabled unless NDEBUG
is defined – which most apps don't do.
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.
@nguyenhuy Since this is a failure case when the app exits I'm wondering if there's a solution which doesn't pollute client (to the lock) code. It seems that there is no user facing cost to these crashes?
While this is more formally correct, the react solution seems cleaner and likely has the same user facing impacts?
@@ -46,28 +46,42 @@ @interface ASBasicImageDownloaderContext () | |||
@implementation ASBasicImageDownloaderContext | |||
|
|||
static NSMutableDictionary *currentRequests = nil; | |||
static ASDN::RecursiveMutex currentRequestsLock; | |||
static ASDN::StaticMutex currentRequestsLock = ASDISPLAYNODE_MUTEX_INITIALIZER; |
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.
I hope for no good reason! Otherwise deadlocks…
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.
Awesome work @nguyenhuy. I would agree with @garrettmoon. The realm solution seems may a bit more simpler and we can repeat this pattern in other places if this repeats.
Otherwise it may makes it harder to change code were we handling the unlock of the lock.
@3a4oT To answer your questions:
|
@Adlai-Holler Good idea. I went ahead and convert all assertions in @garrettmoon @maicki Thinking again, my approach requires more effort on client-side and so it is not scalable. I changed to the approach used in Realm. |
@@ -46,11 +46,12 @@ @interface ASBasicImageDownloaderContext () | |||
@implementation ASBasicImageDownloaderContext | |||
|
|||
static NSMutableDictionary *currentRequests = nil; | |||
static ASDN::RecursiveMutex currentRequestsLock; | |||
// Allocate currentRequestsLock on the heap to prevent destruction at app exit (https://github.com/TextureGroup/Texture/issues/136) | |||
static ASDN::StaticMutex& currentRequestsLock = *new ASDN::StaticMutex; |
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.
I double-checked the code here and I'm 99% sure that this mutex doesn't need to be recursive.
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.
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.
Cool :)
Merging. Thanks, everyone! |
…le the app is being terminated (TextureGroup#577) * Fix crashes caused by failing to unlock or destroy a static mutex while the app is being terminated * Allocate static mutexes on the heap memory to avoid destruction at app exit * ASThread to use ASDisplayNodeCAssert() instead of assert()
This is an interesting crash. Here is an example report in Pinterest app, happening on the static
cacheLock
mutex ofASImageNode
:There are other similar crashes related to
__staticMutex
inASTextKitContext
reported in #136. For instance, see thread #0 and #5 in this report, or thread #0 and #14 here.Basically, what's happening is that all static mutexes are destroyed when an app is terminated by the system. At the same time, a static mutex is being unlocked or destroyed on another thread. The unlock or destruction yields a non-zero error code, which triggers an assertion, even in production.
A similar issue was discussed and fixed in Realm-Core (realm/realm-core#2243). For Texture, I went with a different approach that is arguably safer, IMHO. This should fix #136.
(https://www.ibm.com/support/knowledgecenter/en/ssw_i5_54/apis/users_65.htm)