-
Notifications
You must be signed in to change notification settings - Fork 548
Open
Labels
bugIf an issue is a bug or a pull request a bug fixIf an issue is a bug or a pull request a bug fix
Milestone
Description
Consider the following code:
string notificationData =
"""
{
action = "show_pushed_mail";
aps =
{
alert =
{
body = "Compared Exchange Rates are out of tolerance in number of 115.";
subtitle = "[email protected]";
title = "eM Client Licensing";
};
category = "PUSHED_MAIL";
"content-available" = 1;
"mutable-content" = 1;
sound = default;
"thread-id" = "mail_cf73f3bd-1cf9-437c-bc70-4b6bd2b5f7e4";
};
"em-account" = "[email protected]";
"em-account-id" = "cf73f3bd-1cf9-437c-bc70-4b6bd2b5f7e4";
"em-body" = "";
"em-date" = "2024-10-09T01:30:01.0000000Z";
"em-from" = "eM Client Licensing";
"em-from-address" = "[email protected]";
"em-message-path" = "{\n \"Mailbox\": \"INBOX\",\n \"UIDVALIDITY\": \"1117940911\",\n \"UID\": \"317970\",\n \"Message-ID\": \"[email protected]\"\n}";
"em-notification" = Mixed;
"em-notification-id" = 5801afc0ceb977f379adc152333e0d25554a98d4;
"em-subject" = "Compared Exchange Rates are out of tolerance in number of 115.";
"gcm.message_id" = 1728437407395630;
"google.c.a.e" = 1;
"google.c.fid" = eEhP3hWX1U8DuSB9hb3siN;
"google.c.sender.id" = 417058856903;
}
""";
var d = NSData.FromString(notificationData);
NSPropertyListFormat fmt = NSPropertyListFormat.OpenStep;
var userInfo = (NSMutableDictionary)NSPropertyListSerialization.PropertyListWithData(d, ref fmt, out var error);
var apsKey = new NSString("aps");
var data = userInfo
.Where(kv =>
{
var r = !kv.Key.ToString().Equals("aps", StringComparison.OrdinalIgnoreCase);
apsKey.Dispose();
return r;
})
.ToDictionary(kv => kv.Key.ToString(), kv => kv.Value.ToString() ?? string.Empty);
It will reliably crash with ObjectDisposedException
which may be quite unexpected. In fact, this is a very reduced example of a problem that was happening in a multi-threaded application where it was even less obvious.
Why does it crash?
- We create the
NSString
object representing the stringaps
. - When Objective-C enumerates the dictionary keys it reuses the same object, ie. same handle, when enumerating the
aps
key, and that in turns maps to the same managedNSString
object. - Calling
Dispose
on theNSString
causes the managed representation to be invalid and next enumeration of the same key will crash withObjectDisposedException
.
What can we do about it?
Changing the behavior to remove disposed objects from the handle->managed object mapping seems dangerous. (would not help anyway in the original multi-threaded scenario)
Make the Dispose
on immutable poolable classes like NSString
a no-op? Make an analyzer that warns when someone tries to dispose a NSString
instance (would flag the obvious error but not if someone disposes it as NSObject
variable)?
Thoughts?
Metadata
Metadata
Assignees
Labels
bugIf an issue is a bug or a pull request a bug fixIf an issue is a bug or a pull request a bug fix