Skip to content

[xcode14.1] [ObjCRuntime] Change Runtime.GetNSObject<T> to create a new instance if the existing one is of the wrong type. Fixes #13704.#16502

Merged
dalexsoto merged 1 commit intodotnet:xcode14.1from
vs-mobiletools-engineering-service2:backport-pr-16491-to-xcode14.1
Oct 28, 2022
Merged

[xcode14.1] [ObjCRuntime] Change Runtime.GetNSObject<T> to create a new instance if the existing one is of the wrong type. Fixes #13704.#16502
dalexsoto merged 1 commit intodotnet:xcode14.1from
vs-mobiletools-engineering-service2:backport-pr-16491-to-xcode14.1

Conversation

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Objective-C has an optimization where creating an empty dictionary would
return the same instance every time (probably to a constant empty dictionary).

This causes a problem with how we've bound generic dictionaries, because all
empty dictionaries would have the same native handle, even if we'd bound them
with different managed types.

This surfaces in unfortunate ways when we try to look up a managed instance
given a native handle, we find that we already have a managed instance, but
the managed instance is of the wrong type.

Example code:

var a = new NSDictionary ();
var b = new NSDictionary<NSString, NSString> ();
var c = new NSDictionary<NSString, NSObject> ();
Console.WriteLine ($"a: 0x{a.Handle:X}");
Console.WriteLine ($"b: 0x{b.Handle:X}");
Console.WriteLine ($"c: 0x{c.Handle:X}");

would produce something like:

a: 0x0x7fff80821080
b: 0x0x7fff80821080
c: 0x0x7fff80821080

now for this code:

Runtime.GetNSObject<NSDictionary<NSString, NSString>> (b.Handle)

it would throw an exception like this:

Unable to cast object of type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSObject]]' to type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSString]]'

because we'll have the 'c' object (with type NSDictionary<NSString, Object>)
in our dictionary of native handles -> managed instances, and that's not
compatible with the desired return type from GetNSObject
(NSDictionary<NSString, NSString>)

This likely happens with all the non-mutable collection types we have a
generic version of (NSArray, NSDictionary, NSOrderedSet, NSSet).

Fixes #16378.
Fixes #13704.

This PR is somewhat simpler to review by ignoring whitespace: https://github.com/xamarin/xamarin-macios/pull/16491/files?w=1

Backport of #16491

…if the existing one is of the wrong type. Fixes dotnet#13704.

Objective-C has an optimization where creating an empty dictionary would
return the same instance every time (probably to a constant empty dictionary).

This causes a problem with how we've bound generic dictionaries, because all
empty dictionaries would have the same native handle, even if we'd bound them
with different managed types.

This surfaces in unfortunate ways when we try to look up a managed instance
given a native handle, we find that we already have a managed instance, but
the managed instance is of the wrong type.

Example code:

    var a = new NSDictionary ();
    var b = new NSDictionary<NSString, NSString> ();
    var c = new NSDictionary<NSString, NSObject> ();
    Console.WriteLine ($"a: 0x{a.Handle:X}");
    Console.WriteLine ($"b: 0x{b.Handle:X}");
    Console.WriteLine ($"c: 0x{c.Handle:X}");

would produce something like:

    a: 0x0x7fff80821080
    b: 0x0x7fff80821080
    c: 0x0x7fff80821080

now for this code:

    Runtime.GetNSObject<NSDictionary<NSString, NSString>> (b.Handle)

it would throw an exception like this:

    Unable to cast object of type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSObject]]' to type 'Foundation.NSDictionary`2[[Foundation.NSString],[Foundation.NSString]]'

because we'll have the 'c' object (with type `NSDictionary<NSString, Object>`)
in our dictionary of native handles -> managed instances, and that's not
compatible with the desired return type from GetNSObject
(`NSDictionary<NSString, NSString>`)

This likely happens with all the non-mutable collection types we have a
generic version of (NSArray, NSDictionary, NSOrderedSet, NSSet).

Fixes dotnet#16378.
Fixes dotnet#13704.
@vs-mobiletools-engineering-service2 vs-mobiletools-engineering-service2 added backported bug If an issue is a bug or a pull request a bug fix labels Oct 28, 2022
@vs-mobiletools-engineering-service2
Copy link
Collaborator Author

✅ API diff for current PR / commit

Legacy Xamarin (No breaking changes)
  • iOS (no change detected)
  • tvOS (no change detected)
  • watchOS (no change detected)
  • macOS (no change detected)
NET (empty diffs)
  • iOS: (empty diff detected)
  • tvOS: (empty diff detected)
  • MacCatalyst: (empty diff detected)
  • macOS: (empty diff detected)

❗ API diff vs stable (Breaking changes)

Legacy Xamarin (:heavy_exclamation_mark: Breaking changes :heavy_exclamation_mark:)
.NET (:heavy_exclamation_mark: Breaking changes :heavy_exclamation_mark:)
Legacy Xamarin (stable) vs .NET

✅ Generator diff

Generator diff is empty

Pipeline on Agent
Hash: 224f518e3fac468920f8fa375d8fce055156268c [PR build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator Author

📚 [PR Build] Artifacts 📚

Packages generated

View packages

Pipeline on Agent XAMBOT-1191.Monterey'
Hash: 224f518e3fac468920f8fa375d8fce055156268c [PR build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator Author

❌ [PR Build] Tests on macOS M1 - Mac Big Sur (11.5) failed ❌

Failed tests are:

  • monotouch-test

Pipeline on Agent
Hash: 224f518e3fac468920f8fa375d8fce055156268c [PR build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator Author

🚀 [CI Build] Test results 🚀

Test results

✅ All tests passed on VSTS: simulator tests.

🎉 All 223 tests passed 🎉

Tests counts

✅ bcl: All 69 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests: All 1 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 7 tests passed. Html Report (VSDrops) Download
✅ framework: All 8 tests passed. Html Report (VSDrops) Download
✅ generator: All 2 tests passed. Html Report (VSDrops) Download
✅ interdependent_binding_projects: All 7 tests passed. Html Report (VSDrops) Download
✅ install_source: All 1 tests passed. Html Report (VSDrops) Download
✅ introspection: All 8 tests passed. Html Report (VSDrops) Download
✅ linker: All 65 tests passed. Html Report (VSDrops) Download
✅ mac_binding_project: All 1 tests passed. Html Report (VSDrops) Download
✅ mmp: All 2 tests passed. Html Report (VSDrops) Download
✅ mononative: All 12 tests passed. Html Report (VSDrops) Download
✅ monotouch: All 23 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ mtouch: All 1 tests passed. Html Report (VSDrops) Download
✅ xammac: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 8 tests passed. Html Report (VSDrops) Download
✅ xtro: All 2 tests passed. Html Report (VSDrops) Download

Pipeline on Agent
Hash: [PR build]

@dalexsoto dalexsoto merged commit 3536335 into dotnet:xcode14.1 Oct 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backported bug If an issue is a bug or a pull request a bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants