"System.String doesn't implement interface System.Collections.IEnumerator" crash

Using Unity 3.5.6f4 to build for the iPad, we would “randomly” see this error in the Xcode output:

System.String doesn’t implement interface System.Collections.IEnumerator

  • Assertion: should not be reached at mini-trampolines.c:183

Looking at the stack trace in Xcode, I tracked down the offending statement to a foreach block in a UI framework assembly (DLL) that is used by our project. It turns out, that this is a very tricky problem to find and fix, I’m sharing on the forum for “the greater good”, since I have benefited many times from development forums on the Internet.

This problem only occurs on iOS because it is due to a limitation in the Ahead-Of-Time (AOT) compiler that is used to compile Mono byte code into native code. Thus, your app probably runs fine in the Editor, WebPlayer, Windows, Mac, etc. But, on iOS, it will crash, sometimes the crashes will appear to be random.

The reason this crash is occurring is because the IEnumerable.GetEnumerator() is being used instead of the non-generic IEnumerable.GetEnumerator() to get an enumerator object used by foreach iteration blocks. Since IEnumerable is a type of interface dispatch not supported by full AOT (see Redirecting…), the ‘enumerator’ returned by this method is actually a string object (I don’t know why), which results in a crash.

This problem may appear to be random because the ‘GetEnumerator()’ method “found” by foreach could be the System.Collections.IEnumerable (non-generic) interface implemented by the standard Mono/.NET collections, which works as expected. The ordering of the methods is not consistent, so sometimes the generic interface method is used, making the crash seem random.

I’m surprised that collections being iterated by foreach aren’t crashing left and right due to this issue, but I assume that System.Collections.IEnumerable (non-generic) is being found by foreach most of the time or perhaps it’s because when this code is in a separate assembly it gives the AOT compiler additional trouble resolving to the appropriate GetEnumerator() method.

Either way, here is an AOT-safe method to iterate over an IEnumerable collection. Replace the foreach statement(s) where the crash is occurring with this method.

using System;
using System.Linq;
using System.Collections;
using System.Reflection;

namespace Aperture
{
    public class AotSafe
    {
        public static void ForEach<T>(object enumerable, Action<T> action)
        {
            if (enumerable == null)
            {
                return;
            }

            Type listType = enumerable.GetType().GetInterfaces().First(x => !(x.IsGenericType)  x == typeof(IEnumerable));
            if (listType == null)
            {
                throw new ArgumentException("Object does not implement IEnumerable interface", "enumerable");
            }

            MethodInfo method = listType.GetMethod("GetEnumerator");
            if (method == null)
            {
                throw new InvalidOperationException("Failed to get 'GetEnumberator()' method info from IEnumerable type");
            }

            IEnumerator enumerator = null;
            try
            {
                enumerator = (IEnumerator)method.Invoke(enumerable, null);
                if (enumerator is IEnumerator)
                {
                        while (enumerator.MoveNext())
                        {
                            action((T)enumerator.Current);
                        }
                }
                else
                {
                    UnityEngine.Debug.Log(string.Format("{0}.GetEnumerator() returned '{1}' instead of IEnumerator.",
                        enumerable.ToString(),
                        enumerator.GetType().Name));
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
            }
        }
    }
}

Example usage:

                AotSafe.ForEach<object>(ItemsSource, (item) =>
                {
                    // Do something with item from collection ItemsSource                   
                });

where ItemsSource is an IEnumerable container.

It works!

Thank you so much!!!

@FeatureCreep, I would appreciate bug report with repro case attached.
Thanks!

Did you try simply casting the IEnumerable<> to IEnumerable? i.e.

IEnumerable<MyType> items;

foreach(MyType item in (IEnumerable)items)
{
   // ...
}

@JaredThirsk: unfortunately, explicit casting doesn’t fix the problem.

IEnumerable inherits from IEnumerable, so casting to “IEnumerable” doesn’t guarantee you’re going to get the IEnumerable (non-generic) implementation. The first interface that matches IEnumerable will be returned by the cast (which could be IEnumerable).

Are you sure about this? Did you verify my approach doesn’t work via a test?

I thought the problem here was with generic interface dispatch (i.e. IEnumerable), and my understanding is there is only one implementation of the non-generic IEnumerable.GetEnumerator(), and by first casting to IEnumerable (nongeneric), the generic interface dispatch problem is avoided.

As far as the language is concerned, if you are working with IEnumerable, and request “IEnumerator IEnumerable.GetEnumerator()”, it should not matter that the class also implements IEnumerable, which has a method “IEnumerator IEnumerable.GetEnumerator()”. IEnumerable's inheritance simply means the class must also implement IEnumerable – I don’t understand why it would confuse implementations. (As far as mono’s IMT stuff is concerned, I don’t fully understand how it works or the implications of all the bugs Unity’s now ancient 2.6.5 version has.)

I seem to be having the same issue (also randomly happens), but either my stack-trace is wrong or the issue can have a different cause. The stack-trace looks like this :

Thread 20 Crashed:
0   SomeAppName 		0x01242310 g_logv + 160
1   SomeAppName 		0x01242330 g_log + 28
2   SomeAppName 		0x0115827c mono_convert_imt_slot_to_vtable_slot + 216
3   SomeAppName 		0x01155cfc mono_magic_trampoline + 788
4   SomeAppName 		0x00a8fa34 generic_trampoline_0 + 116
5   SomeAppName 		0x00b53cac m_companyName_communications_CommunicationManager_communicationsChannel_OnMessageReceived_object + 40
6   SomeAppName 		0x00b4d698 m_companyName_communications_channel_AbstractChannel_RaiseMessageReceived_object + 96
7   SomeAppName 		0x00b4ffac m_companyName_communications_channel_socket_SocketChannel_connection_OnMessageReceived_byte__ + 108
8   SomeAppName 		0x00b521bc m_companyName_communications_channel_socket_SocketClient_ReceiveCallback_System_IAsyncResult + 2044
9   SomeAppName 		0x00322aa0 m_System_Net_Sockets_Socket_SocketAsyncResult_Complete + 780
10  SomeAppName 		0x00324064 m_System_Net_Sockets_Socket_Worker_Receive + 60
11  SomeAppName 		0x009e2868 m_wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200
12  SomeAppName 		0x011443a4 mono_jit_runtime_invoke + 2152
13  SomeAppName 		0x011e7424 mono_runtime_invoke + 132
14  SomeAppName 		0x011ec218 mono_runtime_invoke_array + 1448
15  SomeAppName 		0x011ec610 mono_message_invoke + 444
16  SomeAppName 		0x01210600 mono_async_invoke + 124
17  SomeAppName 		0x012114f8 async_invoke_io_thread + 452
18  SomeAppName 		0x012186d8 start_wrapper + 496
19  SomeAppName 		0x0123570c thread_start_routine + 284
20  SomeAppName 		0x01251908 GC_start_routine + 92
21  libsystem_c.dylib	0x3a68830e _pthread_start + 306
22  libsystem_c.dylib	0x3a6881d4 thread_start + 4

but the ‘OnMessageReceived’ method looks like this :

private void communicationsChannel_OnMessageReceived(object message)
{

    HandleInboundMessage(message);

}

BUT the ‘HandleInboundMessage’ method does have a foreach in it :

private void HandleInboundMessage(object message)
{
    if (message is IList)
    {
        foreach (object childMessage in (IList)message)
        {
            HandleInboundMessage(childMessage);
        }
    }
    else if (message is AbstractNotification)
    {
        OnServerNotification((AbstractNotification)message);
    }
    else if (message is AbstractResponse)
    {
        OnServerResponse((AbstractResponse)message);
    }
    else
    {
        OnUnknownMessageType(message);
    }
}

Since I’m having issues connecting the iPad to MonoDevelop to debug the application I’m guessing that the method is being called with a list (which would be a ‘List’ instance containing ‘AbstractResponse’ instances), but anyway here’s the exact message I’m getting :

System.String doesn't implement interface System.Collections.IEnumerator
* Assertion: should not be reached at mini-trampolines.c:183

which seems to be the exact same thing as you guys.

Anyway I will try the suggested fix and come back with some news soon.

EDIT : Applying the fix from OP in the ‘foreach’ in ‘HandleInboundMessage’ fixed seems to have fixed the issue, so apparently the stack traces from iOS devices cannot be trusted… Anyway thanks for the fix/help FeatureCreep!

@FeatureCreep - HUGE thank you!

I was getting this error using UniParse serialization on iOS only, replacing all the foreach statements with your class seems to have resolved the “System.String doesn’t implement interface System.Collections.IEnumerator” crashes.

There are a couple of different ways you can solve this… unfortunately none of them are ideal.

1. Solution provided by FeatureCreep
Pros: Retains typing.
Cons: Uses Invoke - should be used sparingly if possible as there’s a performance penalty

  1. Downcasting to IEnumerable as suggested by JaredThirsk
    Pros: Works with minimal amount of code
    Cons: Will cause boxing/unboxing for lists with a Value Type - IEnumerable.GetEnumerator() returns type “object” which will have to be cast back to your original type. For example:
public List<T> GetList(IEnumerable<T> items)
{
     var result = new List<T>();
     var oldItems = (IEnumerable)items;

     foreach(var obj in oldItems)
     {
            result.Add((T)obj);
     }

     return result;
}

3. Convert to Array
Pros: Simple to implement. Prevents boxing and unboxing.
Cons: Higher memory usage for value types as the values would be copied to the new array rather than referenced.

Example:

public List<T> GetList(IEnumerable<T> items)
{
      var result = new List<T>();

      var itemsArray = items.ToArray();
      for(var i = 0; i < itemsArray.Length; i++)
      {
            result.Add(itemsArray[i]);          
      }

      return result;
}

Personally I would go with option #3 unless you’re dealing with a massive list of value types (i.e. List).

There may potentially be another route which I’m investigating… My latest JSON .NET version that will be published soon uses the 3rd approach as it should offer the best performance. But, there is also the possibility of creating a delegate wrapper around GetEnumerator and using it to call the function. It would be a hybrid approach. Essentially it would be FeatureCreep’s approach but rather than using Invoke it would use a delegate proxy to execute the function which offers far superior performance but I’m not positive yet that it will work with AOT.

Sorry… used the wrong CreateDelegate implementation in my first post so I deleted it. Here is the corrected version. I realized that ToArray may not work… But I was bothered by the Invoke in FeatureCreep’s suggestion so I replaced it with a delegate. I’d love for someone to test this and let me know if it works properly. It should perform much quicker:

using System;
using System.Collections;
using System.Linq;

namespace Aperture
{
	public class AotSafe
	{
		//Delegate to return IEnumerator
		private delegate IEnumerator GetEnumerator();

		public static void ForEach<T>(object enumerable, Action<T> action)
		{
			if (enumerable == null)
				return;

			var listType = enumerable.GetType().GetInterfaces().First(x => !(x.IsGenericType)  x == typeof(IEnumerable));

			if (listType == null)
				throw new ArgumentException("Object does not implement IEnumerable interface", "enumerable");

			var method = listType.GetMethod("GetEnumerator");

			if (method == null)
				throw new InvalidOperationException("Failed to get 'GetEnumerator()' method info from IEnumerable type");

			IEnumerator enumerator = null;

			try
			{
				//Create a delegate instance to get the enumerator
				var enumeratorDelegate = (GetEnumerator) Delegate.CreateDelegate(typeof (GetEnumerator), enumerable, method);
				

				//Create the enumerator by executing the delegate.  
				//This is much faster than using Invoke
				enumerator = enumeratorDelegate();

				if (enumerator != null)
				{
					while (enumerator.MoveNext())
					{
						action((T)enumerator.Current);
					}
				}
				else
				{
					UnityEngine.Debug.Log("GetEnumerator() returned null.");
				}
			}
			finally
			{
				var disposable = enumerator as IDisposable;

				if (disposable != null)
					disposable.Dispose();
			}
		}
	}
}

Adding some knowledge to the thread.

The same exception could happens if you build a generic array with null values in UnityScript and try to serialize using JsonFx.

I tried running several timed tests in MS .NET between using the Invoke method and constructing a delegate but didn’t discern any significant difference between the two - although everything one reads online asserts that using MethodInfo.Invoke is much slower. I don’t know, I didn’t really see that. Maybe there’s been optimizations done to the framework since or my testing is simply flawed.

Once I ported it over to Unity and tried running some tests in Mono I got the following error:

pointing to the line where the delegate is actually executed to get the IEnumerator. Not sure what’s going on there since the construction and casting of the delegate seems to be working, but it looks like the result is an invalid delegate.

Finally, a couple of (mostly) insignificant nitpicks - the lines:

var listType = enumerable.GetType().GetInterfaces().First(x => !(x.IsGenericType)  x == typeof(IEnumerable));
if (listType == null)
{
    throw new ArgumentException("Object does not implement IEnumerable interface", "enumerable");
}
var method = listType.GetMethod("GetEnumerator");

could/should simply be

var enumerableType = typeof(IEnumerable);
if(!enumerable.GetType().GetInterfaces().Contains(enumerableType))
{
    throw new ArgumentException("Object does not implement IEnumerable interface", "enumerable");
}
var method = enumerableType.GetMethod("GetEnumerator");

Of course both will throw exceptions if the enumerable object does not actually implement IEnumerable, but you’ll get a generic “sequence contains no matching elements” exception if it throws in the execution of .First. Also, it shouldn’t be necessary to check !x.IsGenericType as typeof(IEnumerable).IsGenericType will always be false as opposed to typeof(IEnumerable<>).IsGenericType which will always be true.

Or else it was intended as is due to the nature of the original problem and I don’t know what I’m talking about.

PS - Oh and I’d suggest caching the IEnumerable Type and GetEnumerator MethodInfo in a static class to limit the amount of reflection as much as possible.

Roland -

Interesting, thanks for the info. My guess is that it’s actually the opposite. Mono probably lacks some of the optimization that the Microsoft implementation uses which makes the delegate version not perform any better.

Update : we had the same issue again in other modules, we managed to get it working by doing a simple

IList myList;

for(int i = 0; i < myList.Count; i++)
{
    var myItem = myList[i];
}

I’ll update if we encounter other issues with this!

Yes this will work just fine as long as you’re working with a list or an array (or a collection that supports indexing) since it doesn’t require an enumerator. If you’re accepting a generic argument though, such as IEnumerable, or working with a Dictionary<TKey, TValue> you don’t have the option of using an indexer which is why you’d need the ForEach implementation.

Also, be careful with generic interface dispatch even with lists! I would expect the following to fail:

IList<MyType> myList;

for(int i = 0; i < myList.Count; i++)
{
    var myItem = myList[i];
}

(Possibly with different failure characteristics depending on whether MyType is a reference or value type, although I expect both to be unreliable.)

Yeah this obviously only works with lists, although you can use regular for loops with IEnumerable (untested on iOs though):

IEnumerable<T> myEnumerable;
for(int i = 0; i < myEnumerable.Count(); i++)
{
    var temp = myEnumerable.ElementAt(i);
}

We’ve also had issues with using ‘IList’ without the generic parameter on iOs (crashes with the same error message when 'foreach’ing over the collection).

I haven’t experienced any issues with this except with List on iOs where the list sometimes becomes filled with 0s.

Did you guys ever file a bug report with UT as requested? If so, what’s the status?

Fix for this bug is scheduled for next upcoming release of Unity

Thanks Mantas! I’m guessing this means that the Mono runtime included with Unity is getting updated? If so, do you know which version it’ll be and is it comparable to the current MonoTouch version (we have tried reproducing our AOT errors on MonoTouch/Xamarin and can’t)?