The internal structure of the jagged array in .NET.

I created a simple gear array:

int[][] a = new int[2][]; for (int i = 0; i < 2; i++) { a[i] = new int[3]; for (int j = 0; j < 3; j++) a[i][j] = i * 3 + j; } 

After that, I started debugging my application and looked at this massive structure in memory (x86):

 0x03022478 0 // SyncBlockIndex (a) 0x0302247C 0x61B8D5BC // TypeHandle (a) 0x03022480 2 // a.Length 0x03022484 0x617A4C8A // ??? 0x03022488 0x03022494 // a[0] 0x0302248C 0x030224AC // a[1] 0x03022490 0 // SyncBlockIndex (a[0]) 0x03022494 0x61B9C448 // TypeHandle (a[0]) 0x03022498 3 // a[0].Length 0x0302249C 0 // a[0][0] 0x030224A0 1 // a[0][1] 0x030224A4 2 // a[0][2] 0x030224A8 0 // SyncBlockIndex (a[1]) 0x030224AC 0x61B9C448 // TypeHandle (a[1]) 0x030224B0 3 // a[1].Length 0x030224B4 3 // a[1][0] 0x030224B8 4 // a[1][1] 0x030224BC 5 // a[1][2] 

I understand almost all the data: SyncBlockIndexes, TypeHandles, Lengths, Elements. But I can not understand only one line:

 0x03022484 0x617A4C8A // ??? 

What it is?

Update 1:

I tried to resolve this address value using the SOS command:

 !DumpArray 0x617A4C8A <Note: this object has an invalid CLASS field> Invalid object !DumpAssembly 0x617A4C8A Fail to fill Assembly !DumpClass 0x617A4C8A Invalid EEClass address !DumpDomain 0x617A4C8A Fail to fill AppDomain !DumpMD 0x617A4C8A 617a4c8a is not a MethodDesc !DumpMT 0x617A4C8A 617a4c8a is not a MethodTable !DumpObj 0x617A4C8A <Note: this object has an invalid CLASS field> Invalid object !DumpSig 0x617A4C8A !DumpSig <sigaddr> <moduleaddr> 

Update 2:

In an array of reference types, this DWORD must mean the address of an element in the MethodTable array. For example, for object[10] this DWORD is the MethodTable address for System.Object . But in the case of int[][] this DWORD is not a valid MethodTable address (I use the DumpMT SOS command to check it).

+4
source share
1 answer

Quote from the SSCLI source code ( \sscli20_20060311\sscli20\clr\src\vm\object.h ):

 // ArrayBase encapuslates all of these details. In theory you should never // have to peek inside this abstraction class ArrayBase : public Object { ... // This MUST be the first field, so that it directly follows Object. This is because // Object::GetSize() looks at m_NumComponents even though it may not be an array (the // values is shifted out if not an array, so it ok). DWORD m_NumComponents; ... // What comes after this conceputally is: // TypeHandle elementType; Only present if the method table is shared among many types (arrays of pointers) // INT32 bounds[rank]; The bounds are only present for Multidimensional arrays // INT32 lowerBounds[rank]; Valid indexes are lowerBounds[i] <= index[i] < lowerBounds[i] + bounds[i] 

The additional word you see should be TypeHandle elementType :

Only shown if the method table is split between many types (pointer arrays)

\sscli20_20060311\sscli20\clr\src\vm\typehandle.h:

 // At the present time a TypeHandle can point at two possible things // // 1) A MethodTable (Intrinsics, Classes, Value Types and their instantiations) // 2) A TypeDesc (all other cases: arrays, byrefs, pointer types, function pointers, generic type variables) 

int[][] is an array of int[] , TypeHandle int[] is TypeDesc. So, the weird data is TypeHandle, but it cannot be resolved using DumpMT because it is not a MethodTable method.

SSCLI, of course, is not a real Microsoft CLR implementation, but I understand that this is a stripped down version of the 2.0 CLR.

+2
source

Source: https://habr.com/ru/post/1501939/


All Articles