2d7edf555f
We're handling `ObjectDisposedException` a bit inconsistently in our bindings. Some, but not all, manual bindings have checks (not all of them are fully consistent) but there's none for generated bindings, which can lead to errors wrt nullability. **Example** ``` [Test] public void IncompleteNullabilityCheck () { NSString s = new NSString ("bonjour"); s.Dispose (); ManagedLayer (s); } void ManagedLayer (NSString s) { // this is similar to the generated binding code if (s == null) throw new ArgumentNullException ("s"); NativeCode (s.Handle); } void NativeCode (IntPtr p) { // let's assume this is native and dereference the pointer if (p == IntPtr.Zero) Assert.Fail ("boo"); } ``` This shows that we can, _if disposed_, provide `nil` to a native API for which we know `nil` is not a valid argument. That can crash a process in a situation that was possible to detect and throw a (catchable) managed exception. Adding dispose checks everywhere could be costly (in size) unless we share that code with the null check (and a few other optimizations could be applied too). Sharing the code would also ensure more consistency across all bindings. **Impact** Here's the IL for an existing `CGColor` constructor that *already* does the dispose check. ``` .method public hidebysig specialname rtspecialname instance void .ctor ( class CoreGraphics.CGColorSpace colorspace, valuetype System.nfloat[] components ) cil managed { // Method begins at RVA 0x20c834 // Code size 82 (0x52) .maxstack 3 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.2 IL_0007: brtrue.s IL_0014 IL_0009: ldstr "components" IL_000e: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0013: throw IL_0014: ldarg.1 IL_0015: brtrue.s IL_0022 IL_0017: ldstr "colorspace" IL_001c: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0021: throw IL_0022: ldarg.1 IL_0023: ldfld native int CoreGraphics.CGColorSpace::handle IL_0028: ldsfld native int [mscorlib]System.IntPtr::Zero IL_002d: call bool [mscorlib]System.IntPtr::op_Equality(native int, native int) IL_0032: brfalse.s IL_003f IL_0034: ldstr "colorspace" IL_0039: newobj instance void [mscorlib]System.ObjectDisposedException::.ctor(string) IL_003e: throw IL_003f: ldarg.0 IL_0040: ldarg.1 IL_0041: ldfld native int CoreGraphics.CGColorSpace::handle IL_0046: ldarg.2 IL_0047: call native int CoreGraphics.CGColor::CGColorCreate(native int, valuetype System.nfloat[]) IL_004c: stfld native int CoreGraphics.CGColor::handle IL_0051: ret } // end of method CGColor::.ctor Here's the IL code (as committed) using a helper extension method. ``` .method public hidebysig specialname rtspecialname instance void .ctor ( class CoreGraphics.CGColorSpace colorspace, valuetype System.nfloat[] components ) cil managed { // Method begins at RVA 0x210558 // Code size 46 (0x2e) .maxstack 3 .locals init ( [0] native int handleof_colorspace ) IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.2 IL_0007: brtrue.s IL_0014 IL_0009: ldstr "components" IL_000e: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0013: throw IL_0014: ldarg.1 IL_0015: ldstr "colorspace" IL_001a: call native int ObjCRuntime.NativeObjectHelper::GetNonNullHandle(class ObjCRuntime.INativeObject, string) IL_001f: stloc.0 IL_0020: ldarg.0 IL_0021: ldloc.0 IL_0022: ldarg.2 IL_0023: call native int CoreGraphics.CGColor::CGColorCreate(native int, valuetype System.nfloat[]) IL_0028: stfld native int CoreGraphics.CGColor::handle IL_002d: ret } // end of method CGColor::.ctor ``` So existing checks becomes a lot smaller. Here's another example where a dispose check is **missing** (on `pattern`). Note that the check for `colorspace` is not updated so we can see the impact of adding missing dispose checks in existing code (manual or generated). ``` .method public hidebysig specialname rtspecialname instance void .ctor ( class CoreGraphics.CGColorSpace colorspace, class CoreGraphics.CGPattern pattern, valuetype System.nfloat[] components ) cil managed { // Method begins at RVA 0x210660 // Code size 126 (0x7e) .maxstack 4 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.1 IL_0007: brtrue.s IL_0014 IL_0009: ldstr "colorspace" IL_000e: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0013: throw IL_0014: ldarg.1 IL_0015: ldfld native int CoreGraphics.CGColorSpace::handle IL_001a: ldsfld native int [mscorlib]System.IntPtr::Zero IL_001f: call bool [mscorlib]System.IntPtr::op_Equality(native int, native int) IL_0024: brfalse.s IL_0031 IL_0026: ldstr "colorspace" IL_002b: newobj instance void [mscorlib]System.ObjectDisposedException::.ctor(string) IL_0030: throw IL_0031: ldarg.2 IL_0032: brtrue.s IL_003f IL_0034: ldstr "pattern" IL_0039: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_003e: throw IL_003f: ldarg.3 IL_0040: brtrue.s IL_004d IL_0042: ldstr "components" IL_0047: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_004c: throw IL_004d: ldarg.0 IL_004e: ldarg.1 IL_004f: ldfld native int CoreGraphics.CGColorSpace::handle IL_0054: ldarg.2 IL_0055: callvirt instance native int CoreFoundation.NativeObject::get_Handle() IL_005a: ldarg.3 IL_005b: call native int CoreGraphics.CGColor::CGColorCreateWithPattern(native int, native int, valuetype System.nfloat[]) IL_0060: stfld native int CoreGraphics.CGColor::handle IL_0065: ldarg.0 IL_0066: ldfld native int CoreGraphics.CGColor::handle IL_006b: ldsfld native int [mscorlib]System.IntPtr::Zero IL_0070: call bool [mscorlib]System.IntPtr::op_Equality(native int, native int) IL_0075: brfalse.s IL_007d IL_0077: newobj instance void [mscorlib]System.ArgumentException::.ctor() IL_007c: throw IL_007d: ret } // end of method CGColor::.ctor ``` into ``` .method public hidebysig specialname rtspecialname instance void .ctor ( class CoreGraphics.CGColorSpace colorspace, class CoreGraphics.CGPattern pattern, valuetype System.nfloat[] components ) cil managed { // Method begins at RVA 0x210660 // Code size 119 (0x77) .maxstack 4 .locals init ( [0] native int handleof_pattern ) IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.1 IL_0007: brtrue.s IL_0014 IL_0009: ldstr "colorspace" IL_000e: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_0013: throw IL_0014: ldarg.1 IL_0015: ldfld native int CoreGraphics.CGColorSpace::handle IL_001a: ldsfld native int [mscorlib]System.IntPtr::Zero IL_001f: call bool [mscorlib]System.IntPtr::op_Equality(native int, native int) IL_0024: brfalse.s IL_0031 IL_0026: ldstr "colorspace" IL_002b: newobj instance void [mscorlib]System.ObjectDisposedException::.ctor(string) IL_0030: throw IL_0031: ldarg.3 IL_0032: brtrue.s IL_003f IL_0034: ldstr "components" IL_0039: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) IL_003e: throw IL_003f: ldarg.2 IL_0040: ldstr "pattern" IL_0045: call native int ObjCRuntime.NativeObjectHelper::GetNonNullHandle(class ObjCRuntime.INativeObject, string) IL_004a: stloc.0 IL_004b: ldarg.0 IL_004c: ldarg.1 IL_004d: ldfld native int CoreGraphics.CGColorSpace::handle IL_0052: ldloc.0 IL_0053: ldarg.3 IL_0054: call native int CoreGraphics.CGColor::CGColorCreateWithPattern(native int, native int, valuetype System.nfloat[]) IL_0059: stfld native int CoreGraphics.CGColor::handle IL_005e: ldarg.0 IL_005f: ldfld native int CoreGraphics.CGColor::handle IL_0064: ldsfld native int [mscorlib]System.IntPtr::Zero IL_0069: call bool [mscorlib]System.IntPtr::op_Equality(native int, native int) IL_006e: brfalse.s IL_0076 IL_0070: newobj instance void [mscorlib]System.ArgumentException::.ctor() IL_0075: throw IL_0076: ret } // end of method CGColor::.ctor ``` so the difference is smaller, but it's still smaller (7 bytes) than the existing code (that did not check for a disposed instance). There are many more optimizations that can be applied on top of this. However the main/original goal is to have a correct and consistent handling of disposed managed instances. IOW the size reduction is a nice side-effect of correctness and actual optimizations can come later :) Add `ObjectDisposedException` when required on Handle access. Instead of providing `nil` to native API that are decorated **not** accepting them. Also do this using existing and new extension method helpers so the IL size of the assemblies is (a bit) smaller than the existing code. The latter has a small, positive impact for Xamarin.Mac (JIT'ing or requiring IL for, non-full, AOT'ing) and for Xamarin.iOS when the interpreter is used. |
||
---|---|---|
.github/workflows | ||
builds | ||
docs | ||
dotnet | ||
external | ||
fsharp | ||
jenkins | ||
mk | ||
mono | ||
msbuild | ||
opentk | ||
runtime | ||
src | ||
tests | ||
tools | ||
.editorconfig | ||
.gitignore | ||
.gitmodules | ||
CODEOWNERS | ||
ISSUE_TEMPLATE.md | ||
LICENSE | ||
Make.config | ||
Make.versions | ||
Makefile | ||
NOTICE.txt | ||
NuGet.config | ||
README.md | ||
SECURITY.MD | ||
Versions-ios.plist.in | ||
Versions-mac.plist.in | ||
Xamarin.Mac.sln | ||
Xamarin.iOS.sln | ||
banner.png | ||
configure | ||
mac-entitlements.plist | ||
product.snk | ||
system-dependencies.sh | ||
versions-check.csharp |
README.md
Xamarin.iOS & Xamarin.Mac
Welcome!
This module is the main repository for both Xamarin.iOS and Xamarin.Mac.
These SDKs allow us to create native iOS, tvOS, watchOS and macOS applications using the same UI controls we would in Objective-C and Xcode, except with the flexibility and elegance of a modern language (C#), the power of the .NET Base Class Library (BCL), and two first-class IDEs—Visual Studio for Mac and Visual Studio—at our fingertips.
This repository is where we do development for the Xamarin.iOS and Xamarin.Mac SDKs. There are a few ways that you can contribute, for example:
- Submit bugs and feature requests
- Review source code changes
- Submit pull requests to resolve issues and fix bugs
Contributing
If you are interested in fixing issues and contributing directly to the code base, please see the document How to Contribute, which covers the following:
- How to build and run from source
- The development workflow, including debugging and running tests
- Coding Guidelines
- Submitting pull requests
Downloads
The preferred method for installing Xamarin.iOS and Mac is to use the Visual Studio installers (Windows, Mac).
The team also strongly recommends using the latest Xamarin SDK and Xcode whenever possible.
However, we provide links to older Xamarin.iOS and Mac packages for macOS downgrades and build machine configuration.
Version | Xamarin.iOS | Xamarin.Mac |
---|---|---|
d16.7 | 14.2.0.12 | 6.20.2.2 |
d16.6 | 13.18.2.1 | 6.18.2.1 |
d16.5 | 13.16.0.13 | 6.16.0.13 |
d16.4 | 13.10.0.21 | 6.10.0.21 |
d16.3 | 13.6.0.12 | 6.6.0.12 |
d16.2 | 12.14.0.114 | 5.14.0.114 |
d16.1 | 12.10.0.157 | 5.10.0.157 |
d16.0 | 12.8.0.2 | 5.8.0.0 |
Feedback
- Ask a question on Stack Overflow or the Xamarin Forums
- Request a new feature on GitHub
- Vote on existing feature requests
- Submit bugs to GitHub Issues
- Discuss development and design on Discord
License
Copyright (c) .NET Foundation Contributors. All rights reserved. Licensed under the MIT License.