From 2e10c89828750884eddf1759571108e4f0023d2d Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Wed, 13 Nov 2019 14:23:09 -0500 Subject: [PATCH 1/2] [CoreFoundation] CFBundle.GetAll better thread safe. The initial solution fixed the rance condition in which the index changed, but that did not guarantee that we would get the correct bundles. We now clone the CFArray (which also clones the callbacks set to the array) and iterate over it to make sure Apple does not do evil tings while we are iteraing. Better Fixes: https://github.com/xamarin/maccore/issues/940 --- src/CoreFoundation/CFBundle.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/CoreFoundation/CFBundle.cs b/src/CoreFoundation/CFBundle.cs index 5989890bd407..581e73112a13 100644 --- a/src/CoreFoundation/CFBundle.cs +++ b/src/CoreFoundation/CFBundle.cs @@ -109,14 +109,16 @@ public static CFBundle[] GetAll () // 'This function is potentially expensive and not thread-safe' // // This means, that we should not trust the size of the array, since is a get and - // might be modified by a diff thread. We just use the size returned by the first - // count to avoid a System.IndexOutOfRangeException when looping - using (var cfBundles = new CFArray (CFBundleGetAllBundles ())) { - var bundleCount = cfBundles.Count; + // might be modified by a diff thread. We are going to clone the array and make sure + // that Apple does not modify the array while we work with it. That avoids changes + // in the index or in the bundles returned. + using (var cfBundles = new CFArray (CFBundleGetAllBundles ())) + using (var cfBundlesCopy = cfBundles.Clone () ) { + var bundleCount = cfBundlesCopy.Count; // the property is a C call, calling everytime we loop is not needed var managedBundles = new CFBundle [bundleCount]; for (int index = 0; index < bundleCount; index++) { // follow the get rule, we do not own the object - managedBundles [index] = new CFBundle (cfBundles.GetValue (index), false); + managedBundles [index] = new CFBundle (cfBundlesCopy.GetValue (index), false); } return managedBundles; } From 4eaca4e144a4b2f477c9ba08bb6073e4a82e2304 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Wed, 13 Nov 2019 06:06:23 -0500 Subject: [PATCH 2/2] [CoreFoundation] Add Clone method for CFArray. (#7403) When working on https://github.com/xamarin/maccore/issues/940 we noticed that clone the array would be a better approach. The CFArrayCreateCopy add some nice things: * The pointer values from theArray are copied into the new array. * The values are also retained by the new array. * The count of the new array is the same as theArray * The new array uses the same callbacks as theArray. [IMPORTANT] Whith this in, we can have a better fix for https://github.com/xamarin/maccore/issues/940 --- src/CoreFoundation/CFArray.cs | 7 +++++++ tests/xtro-sharpie/common-CoreFoundation.ignore | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/CoreFoundation/CFArray.cs b/src/CoreFoundation/CFArray.cs index 7f5df0e79557..d3b9dd5f08c3 100644 --- a/src/CoreFoundation/CFArray.cs +++ b/src/CoreFoundation/CFArray.cs @@ -35,6 +35,8 @@ using ObjCRuntime; using CFIndex = System.nint; +using CFArrayRef = System.IntPtr; +using CFAllocatorRef = System.IntPtr; namespace CoreFoundation { @@ -149,6 +151,11 @@ public static nint GetCount (IntPtr array) { return CFArrayGetCount (array); } + + [DllImport (Constants.CoreFoundationLibrary)] + extern static CFArrayRef CFArrayCreateCopy (CFAllocatorRef allocator, CFArrayRef theArray); + + public CFArray Clone () => new CFArray (CFArrayCreateCopy (IntPtr.Zero, this.Handle), true); } } diff --git a/tests/xtro-sharpie/common-CoreFoundation.ignore b/tests/xtro-sharpie/common-CoreFoundation.ignore index 3db8cadbd88d..ee1d3a96ee1d 100644 --- a/tests/xtro-sharpie/common-CoreFoundation.ignore +++ b/tests/xtro-sharpie/common-CoreFoundation.ignore @@ -334,7 +334,6 @@ !missing-pinvoke! CFArrayApplyFunction is not bound !missing-pinvoke! CFArrayBSearchValues is not bound !missing-pinvoke! CFArrayContainsValue is not bound -!missing-pinvoke! CFArrayCreateCopy is not bound !missing-pinvoke! CFArrayCreateMutable is not bound !missing-pinvoke! CFArrayCreateMutableCopy is not bound !missing-pinvoke! CFArrayExchangeValuesAtIndices is not bound