Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read array initializer values from .NET assembly

How is it possible to read the values, let's say: '99' from an assembly containing this code?

using Sytem; 

public class Class1
{
    public Class1() {
        // array initializer, want to read '99', '100'... from assembly
        var a = new double[,] { { 1, 2, 3 }, { 99, 100, 101 } };
        // ...
    }

}

What I have done so far

The method in ILDASM:

.method /*06000001*/ public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
// SIG: 20 00 01
{
  // Method begins at RVA 0x2080
  // Code size       29 (0x1d)
  .maxstack  3
  .locals /*11000001*/ init ([0] float64[0...,0...] a)
  .language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
// Source File 'c:\Users\heini19\Documents\Visual Studio 2013\Projects\WcfService1\ClassLibrary1\Class1.cs' 
//000005:         public Class1() {
  IL_0000:  /* 02   |                  */ ldarg.0
  IL_0001:  /* 28   | (0A)000011       */ call       instance void [mscorlib/*23000001*/]System.Object/*01000001*/::.ctor() /* 0A000011 */
  IL_0006:  /* 00   |                  */ nop
  IL_0007:  /* 00   |                  */ nop
//000006:             // array initializer, want to read '99', '100' etc.
//000007:             var a = new double[,] { { 1, 2, 3 }, { 99, 100, 101 } };
  IL_0008:  /* 18   |                  */ ldc.i4.2
  IL_0009:  /* 19   |                  */ ldc.i4.3
  IL_000a:  /* 73   | (0A)000012       */ newobj     instance void float64[0...,0...]/*1B000001*/::.ctor(int32,
                                                                                                         int32) /* 0A000012 */
  IL_000f:  /* 25   |                  */ dup
  IL_0010:  /* D0   | (04)000001       */ ldtoken    field valuetype '<PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}'/*02000003*//'__StaticArrayInitTypeSize=48'/*02000004*/ '<PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}'/*02000003*/::'$$method0x6000001-1' /* 04000001 */
  IL_0015:  /* 28   | (0A)000014       */ call       void [mscorlib/*23000001*/]System.Runtime.CompilerServices.RuntimeHelpers/*01000015*/::InitializeArray(class [mscorlib/*23000001*/]System.Array/*01000016*/,
                                                                                                                                                            valuetype [mscorlib/*23000001*/]System.RuntimeFieldHandle/*01000017*/) /* 0A000014 */
  IL_001a:  /* 0A   |                  */ stloc.0
//000008:             // ...
//000009:         }
  IL_001b:  /* 00   |                  */ nop
  IL_001c:  /* 2A   |                  */ ret
} // end of method Class1::.ctor

The compiler created the struct <PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4} with the field $$method0x6000001-1 for the initialization value and uses RuntimeHelpers.InitializeArray in order to initialize the new array at runtime. The original values defined in C# seem to be stored in the field and get copied by using the field handle? But how are the values laid out?

There must be some better/easier way to read those constants from the assembly?

like image 729
Haymo Kutschbach Avatar asked May 23 '15 15:05

Haymo Kutschbach


1 Answers

non response

What you are trying to do verge on the impossible (note that the single case in your example is probably doable, but probably wouldn't cover your full needs)

The <PrivateImplementationDetails> is created by the C# compiler only in some cases (numeric arrays over a certain size, it seems). For all the other cases, direct initialization in the constructor is done. See http://goo.gl/iC6MRv for some examples.

Note that the IL code you are seeing isn't "written in the stone"... There are no rules that dictate to a C# compiler how it should create array initializers. For example Roslyn (the link I gave is generated by Roslyn) uses a PrivateImplementationDetails instead of <PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}. And who knows what code is generated by the Mono compiler.

In the most general case it isn't possible know the values of an initialized array without executing the constructor (so instantiating the class) and taking a look at the obtained object. But this clearly has other problems (the initialization of a class could have side effects, or could require parameters)

like image 89
xanatos Avatar answered Oct 20 '22 13:10

xanatos