Quantcast
Channel: Visual Studio General Questions forum
Viewing all articles
Browse latest Browse all 21115

ILASM - Serialization of Types in Custom Attributes incorrect

$
0
0

Greetings,

I just wanted to know if anyone else has noticed that ilasm incorrectly encodes type names on CustomAttributes.  Let's give an example:

.assembly SerializationError
{
    .ver 1:0:0:0
    .hash algorithm 0x00008004
}
.module SerializationError.exe
.subsystem 0x0003
// MVID: {4CC49ABD-FEB2-4D33-8FE4-A9FED179B4EA}
// Target Runtime Version: v4.0.30319
// Platform Target : x86
.assembly extern mscorlib
{
    .ver 4:0:0:0
    .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
}

.namespace SerializationError
{
    .class private auto ansi beforefieldinit SerializationTestAttribute
        extends [mscorlib]System.Attribute
    {
        .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = { int32(0x7fff) }
        .method public hidebysig specialname rtspecialname instance void .ctor(class [mscorlib]System.Type target) cil managed
        {
            .maxstack 8
            L_0000: ldarg.0 
            L_0001: call instance void [mscorlib]System.Attribute::.ctor()
            L_0006: nop 
            L_0007: nop 
            L_0008: ldarg.0 
            L_0009: ldarg.1 
            L_000a: stfld class [mscorlib]System.Type SerializationError.SerializationTestAttribute::target
            L_000f: nop 
            L_0010: ret 
        }


        .property instance class [mscorlib]System.Type Target()
        {
            .get instance class [mscorlib]System.Type SerializationError.SerializationTestAttribute::get_Target()
        }
        
	.method public hidebysig specialname instance class [mscorlib]System.Type 
		get_Target() cil managed
	{
	  // Code size       12 (0xc)
	  .maxstack  1
	  .locals init ([0] class [mscorlib]System.Type CS$1$0000)
	  IL_0000:  nop
	  IL_0001:  ldarg.0
	  IL_0002:  ldfld      class [mscorlib]System.Type SerializationError.SerializationTestAttribute::target
	  IL_0007:  stloc.0
	  IL_0008:  br.s       IL_000a
	  IL_000a:  ldloc.0
	  IL_000b:  ret
	} // end of method SerializationTestAttribute::get_Target



        .field private class [mscorlib]System.Type target

    }
    .class private auto ansi beforefieldinit 'Serialization+Test+Class'
        extends [mscorlib]System.Object
    {
        .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
        {
            .maxstack 8
            L_0000: ldarg.0 
            L_0001: call instance void [mscorlib]System.Object::.ctor()
            L_0006: ret 
        }

    }
    .class private abstract auto ansi sealed beforefieldinit SerializationTestProgram
        extends [mscorlib]System.Object
    {
//        .custom instance void SerializationError.SerializationTestAttribute::.ctor(class [mscorlib]System.Type) = { type(SerializationError.'Serialization+Test+Class') }
/* *
 * The above line generates the following metadata entry:
 * .custom instance void SerializationError.SerializationTestAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 2B 53 65 72 69 61 6C 69 7A 61 74 69 6F 6E   // ..+Serialization
 *                                                                                                             45 72 72 6F 72 2E 53 65 72 69 61 6C 69 7A 61 74   // Error.Serializat
 *                                                                                                             69 6F 6E 2B 54 65 73 74 2B 43 6C 61 73 73 00 00 ) // ion+Test+Class..
 * The proper value is shown below:
 * */
   .custom instance void SerializationError.SerializationTestAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 2D 53 65 72 69 61 6C 69 7A 61 74 69 6F 6E         // ..-Serialization
                                                                                                               45 72 72 6F 72 2E 53 65 72 69 61 6C 69 7A 61 74         // Error.Serializat
                                                                                                               69 6F 6E 5C 2B 54 65 73 74 5C 2B 43 6C 61 73 73 00 00 ) // ion\+Test\+Class..

 
        .method private hidebysig static void Main(string[] args) cil managed
        {
            .entrypoint
            .maxstack 3
            .locals init (
                [0] class [mscorlib]System.Type 'type',
                [1] class SerializationError.SerializationTestAttribute attribute)
            L_0000: nop 
            L_0001: ldtoken SerializationError.SerializationTestProgram
            L_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            L_000b: stloc.0 
            L_000c: ldloc.0 
            L_000d: ldtoken SerializationError.SerializationTestAttribute
            L_0012: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            L_0017: ldc.i4.1 
            L_0018: callvirt instance object[] [mscorlib]System.Reflection.MemberInfo::GetCustomAttributes(class [mscorlib]System.Type, bool)
            L_001d: ldc.i4.0 
            L_001e: ldelem.ref 
            L_001f: castclass SerializationError.SerializationTestAttribute
            L_0024: stloc.1 
            L_0025: ldloc.1 
            L_0026: callvirt instance class [mscorlib]System.Type SerializationError.SerializationTestAttribute::get_Target()
            L_002b: call void [mscorlib]System.Console::WriteLine(object)
            L_0030: nop 
            L_0031: ret 
        }

    }
}

The type SerializationError.'Serialization+Test+Class' when used within type() on a custom attribute, accepting a type, yields a serialized string which doesn't escape the '+' characters within the name, when reflection attempts to parse the value from the custom attribute's SerString, a type load exception results, because it's looking for nested types.

From what I can tell, ilasm doesn't encode any special characters, I also haven't been able to find a way to escape the characters intentionally, using '\\' within the actual typename yields it trying to look up a type with the escape character in the type name.  Using one backslash in the typename to get '\' yields the same string without the backslashes being serialized.


Viewing all articles
Browse latest Browse all 21115

Trending Articles