-
Notifications
You must be signed in to change notification settings - Fork 129
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 possible crash or deadlock arising from calling notify() from multiple queues concurrently #401
Fix possible crash or deadlock arising from calling notify() from multiple queues concurrently #401
Conversation
Removed inlining/static to be compatible with C++ handler
Allows the system to have multiple crash report paths for different contexts
Allows each report generator to use a different context if needed
While not async signal safe, this interface is suitable for generating IDs on the fly when calling reportUserException().
This change allows each notify request to specify its own crash ID and file path, avoiding cases where two notify calls either reuse the same file path or stomp on each other when trying to set the "next" ID/path.
This avoids multiple threads from notify() stomping on this file
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.
LGTM 👍
One suggestion for a unit test to cover new function (if feasible).
@interface KSCrashIdentifierTests : XCTestCase | ||
@end | ||
|
||
@implementation KSCrashIdentifierTests |
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.
Can we include a test for bsg_kscrash_generate_report_path
?
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.
Yeah I should - it turned out to be a bit tricky to stub the file store but I've added a task to improve coverage here.
When will a new release be ready? Thanks. |
Hi @nkavian! Doing a release now, should be available soon. |
Thanks, confirming the latest release fixed my issue! |
In the new Xcode 10 build system, Swift object register values have the top bit used as a flag. This change strips the flag while not losing anything relevant to us in our quest to see error messages for assertion failures. This technique does not capture messages which are less than 16 characters, as short strings are stored as raw char arrays on the stack rather than being allocated. (See WWDC 2018 bugsnag#401 for more info on new string optimizations) While it is possible to check for char arrays as well as pointers when searching for notable address values, sweeping up local variables has a likely chance of capturing unintended data as well from the surrounding code, some of which may be sensitive. It is also not guaranteed that the value would still be on the stack after the message is logged, so it is possible to get only unrelated string values as the message. In the current Swift stdlib, the following messages passed to fatalError, preconditionFailure, and precondition (and their internal func counterparts) are less than 16 characters: * empty string * `unavailable` * `not implemented` * `abstract method` * `unknown value` * `invalid count` (where a dictionary contains < 0 items(?)) * `invalid index` (where a dictionary ceases to be a dictionary) * `don't touch me` (from SpriteKit) * `close() failed` (from the private Subprocess implementation) The vast majority have more meaningful messages. Reference: * https://asciiwwdc.com/2018/sessions/401 Fixes bugsnag#318
Goal
Its possible that when
notify()
is called concurrently from multiple queues, that a crash occurs when caching/resetting crash state. This changeset solves the underlying issues by not sharing state between calls tonotify()
and isolating calls to suspend threads (for backtrace collection).Reproduction case
Fixes #399
Changeset
The changes can be divided into four parts:
notify()
several times from different concurrent queuesnotify()
notify()
callsThe easiest way to view the changeset is one commit at a time, since each chunk can be evaluated independently.
Tests