Skip to content

System.BadImageFormatException when reflecting on BCL shipped with Mono #17278

Closed

Description

@joncham

Mono throws exception when methods in the BCL are queried for custom attributes.

Steps to Reproduce

  1. Run test case below
using System;
using System.Reflection;
using System.Linq;
using System.IO;

internal class Program
{
    public static int Main(string[] args)
    {
        foreach (Type type in typeof(System.Linq.Enumerable).Assembly.GetTypes())
        {
            foreach (MemberInfo method in type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                try
                {
                    method.GetCustomAttributes<DummyAttribute>();
                }
                catch (BadImageFormatException)
                {
                    Console.WriteLine($"BadImageFormatException {type}:{method}");
                    throw;
                }
            }
        }
        return 0;
    }
}

class DummyAttribute : Attribute
{

}

Current Behavior

System.Linq.Parallel.GroupJoinQueryOperator`4[TLeftInput,TRightInput,TKey,TOutput]:System.Linq.Parallel.QueryResults`1[TOutput] Open(System.Linq.Parallel.QuerySettings, Boolean)

Unhandled Exception:
System.BadImageFormatException: VAR 3 (TOutput) cannot be expanded in this context with 3 instantiations
  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.get_base_method(System.Reflection.RuntimeMethodInfo,bool)
  at System.Reflection.RuntimeMethodInfo.GetBaseMethod () [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.MonoCustomAttrs.GetBase (System.Reflection.ICustomAttributeProvider obj) [0x000ad] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.MonoCustomAttrs.GetCustomAttributes (System.Reflection.ICustomAttributeProvider obj, System.Type attributeType, System.Boolean inherit) [0x000b5] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Reflection.RuntimeMethodInfo.GetCustomAttributes (System.Type attributeType, System.Boolean inherit) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Attribute.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type type, System.Boolean inherit) [0x00088] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Attribute.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type type) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Reflection.CustomAttributeExtensions.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type attributeType) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Reflection.CustomAttributeExtensions.GetCustomAttributes[T] (System.Reflection.MemberInfo element) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at Program.Main (System.String[] args) [0x00057] in <a28b7bf7d0b34731b1ba0283bc2d394c>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.BadImageFormatException: VAR 3 (TOutput) cannot be expanded in this context with 3 instantiations
  at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.get_base_method(System.Reflection.RuntimeMethodInfo,bool)
  at System.Reflection.RuntimeMethodInfo.GetBaseMethod () [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.MonoCustomAttrs.GetBase (System.Reflection.ICustomAttributeProvider obj) [0x000ad] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.MonoCustomAttrs.GetCustomAttributes (System.Reflection.ICustomAttributeProvider obj, System.Type attributeType, System.Boolean inherit) [0x000b5] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Reflection.RuntimeMethodInfo.GetCustomAttributes (System.Type attributeType, System.Boolean inherit) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Attribute.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type type, System.Boolean inherit) [0x00088] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Attribute.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type type) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Reflection.CustomAttributeExtensions.GetCustomAttributes (System.Reflection.MemberInfo element, System.Type attributeType) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at System.Reflection.CustomAttributeExtensions.GetCustomAttributes[T] (System.Reflection.MemberInfo element) [0x00000] in <b814b509d4ad406fb40c6c93e38929e7>:0 
  at Program.Main (System.String[] args) [0x00057] in <a28b7bf7d0b34731b1ba0283bc2d394c>:0 

Expected Behavior

No Exception

On which platforms did you notice this

[X ] macOS
[ ] Linux
[ X] Windows

Version Used:

Mono JIT compiler version 6.4.0.198 (2019-06/fe64a4765e6 Wed Sep 18 14:14:51 EDT 2019)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
	TLS:           
	SIGSEGV:       altstack
	Notification:  kqueue
	Architecture:  amd64
	Disabled:      none
	Misc:          softdebug 
	Interpreter:   yes
	LLVM:          yes(610)
	Suspend:       hybrid
	GC:            sgen (concurrent by default)

Corresponds to Unity Issue: https://issuetracker.unity3d.com/issues/badimageformatexception-is-thrown-when-calling-getcustomattributes-on-certain-memberinfo-instances

Activity

  1. changed the title [-]System.BadImageFormatException when reflection on class libraries[/-] [+]System.BadImageFormatException when reflecting on BCL shipped with Mono[/+] on Oct 10, 2019
  2. marek-safar commented on Oct 10, 2019

    @marek-safar
    Member
  3. self-assigned this
    on Oct 10, 2019
  4. QFSW commented on Oct 11, 2019

    @QFSW

    Original reporter of the issue, wondering if it's possible for this exception to be thrown when inspecting user code or if it is safe to ignore

  5. joncham commented on Oct 11, 2019

    @joncham
    ContributorAuthor

    @QFSW I think this is problem related to complex usage of generic parameters with inheritance, so I expect this could show up in any code but very unlikely.

  6. QFSW commented on Oct 11, 2019

    @QFSW

    @QFSW I think this is problem related to complex usage of generic parameters with inheritance, so I expect this could show up in any code but very unlikely.

    Gotcha, in that case the chance of it popping up in user code AND being something I'm even remotely interested in are remotely small, thanks

  7. baulig commented on Oct 17, 2019

    @baulig
    Contributor

    This seems to come from this block here:

    mono/mono/metadata/class.c

    Lines 726 to 738 in e5721bb

    MonoGenericParam *gparam = type->data.generic_param;
    if (num >= inst->type_argc) {
    const char *pname = mono_generic_param_name (gparam);
    mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
    num, pname ? pname : "", inst->type_argc);
    return NULL;
    }
    if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) {
    const char *pname = mono_generic_param_name (gparam);
    mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
    num, pname ? pname : "", inst->type_argv [num]->type);
    return NULL;
    }

    The can_inflate_gparam_with() call this:

    mono/mono/metadata/class.c

    Lines 625 to 637 in e5721bb

    gboolean
    mono_type_is_valid_generic_argument (MonoType *type)
    {
    switch (type->type) {
    case MONO_TYPE_VOID:
    case MONO_TYPE_TYPEDBYREF:
    return FALSE;
    case MONO_TYPE_VALUETYPE:
    return !m_class_is_byreflike (type->data.klass);
    default:
    return TRUE;
    }
    }

    So it could be an unexpected type or too many generic argument / too complex of a generic instantiation for the code to handle it properly.

  8. lambdageek commented on Oct 21, 2019

    @lambdageek
    Member

    Thanks Martin!

    It's happening when we're looking at this method: https://github.com/dotnet/corefx/blob/b49a8a9be1d53cd9e50cb68fd8540be25c65d433/src/System.Linq.Parallel/src/System/Linq/Parallel/QueryOperators/Binary/GroupJoinQueryOperator.cs#L64 which is an override in a child class that has 4 generic type parameters of a method that comes from a base class that has 3 generic type parameters. So at some point we started looking at the wrong context.

  9. lambdageek commented on Oct 21, 2019

    @lambdageek
    Member

    Standalone repro

    using System;
    using System.Reflection;
    using System.IO;
    
    public abstract class One<C> {
    	public abstract C Foo ();
    }
    
    public abstract class Three<A,B,C> : One<C> {
    }
    
    public class Four<X, Y, Z, W> : Three <Y, Z, W> {
    	public override W Foo () {
    		throw new Exception ("Four");
    	}
    }
    
    internal class Program
    {
        public static int Main(string[] args)
        {
    	    var type = typeof (Four<,,,>);
    	    var method = type.GetMethod ("Foo");
                    try
                    {
                        method.GetCustomAttributes<DummyAttribute>();
                    }
                    catch (BadImageFormatException)
                    {
                        Console.WriteLine($"BadImageFormatException {type}:{method}");
                        throw;
                    }
            return 0;
        }
    
    }
    
    class DummyAttribute : Attribute
    {
    
    }
  10. lambdageek commented on Oct 21, 2019

    @lambdageek
    Member

    Broken since at least 5.12.0.311 (2018-02)

  11. added this to the 2019-10 (6.8.xx) milestone on Oct 22, 2019
  12. lambdageek commented on Oct 22, 2019

    @lambdageek
    Member

    Keeping open until the 2019-10 backport lands

  13. added a commit that references this issue on Jan 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions