Как определить тип массива?
У меня есть OutOfMemoryException, и я хотел бы проанализировать размер и тип массива, который будет создан.
Я создал демонстрационный дамп для этой ситуации и могу получить следующую информацию:
0:000> !pe
Exception object: 023f389c
Exception type: System.OutOfMemoryException
Message: <none>
InnerException: <none>
StackTrace (generated):
SP IP Function
0015EE44 0099007F OOM2!OOM2.Program.Main()+0xf
StackTraceString: <none>
HResult: 8007000e
0:000> !u 0099007F
Normal JIT generated code
OOM2.Program.Main()
Begin 00990070, size 22
00990070 baffffff7f mov edx,7FFFFFFFh
00990075 b90241a478 mov ecx,offset mscorlib_ni+0x4102 (78a44102)
0099007a e8192194ff call 002d2198 (JitHelp: CORINFO_HELP_NEWARR_1_VC)
>>> 0099007f 8bc8 mov ecx,eax
...
Итак, я вижу, что создан новый массив размером 7FFFFFFF, что составляет 2 миллиарда элементов. (Пожалуйста, игнорируйте тот факт, что вы не можете даже создать байт [] такого размера в 32-разрядном приложении.NET, поэтому в этом примере тип, вероятно, не будет иметь никакого значения.)
Я сейчас прочитал, что тип массива находится в регистре ECX, но, к сожалению, mscorlib_ni+0x4102 (78a44102)
не очень полезно
я пытался !mln
, !mdt
и даже нереально !ip2mt
, но ни один из них не отображает ожидаемый byte
или же byte[]
выход. Есть ли способ получить тип из этого нативного образа mscorlib?
1 ответ
Один из способов сделать это - сбросить IL, соответствующий методу, в котором создается массив.
Во-первых, используйте !clrstack
чтобы получить метод, в котором вы находитесь. В моем случае я нахожусь в фиктивном приложении в Main
метод:
0:000> !clrstack
OS Thread Id: 0x7d0 (0)
Child SP IP Call Site
0016f094 758dc42d [HelperMethodFrame: 0016f094]
0016f120 003200af ConsoleApplication4.Program.Main(System.String[]) [c:\Users\smt\Documents\Visual Studio 2012\Projects\ConsoleApplication4\Program.cs @ 215]
0016f2bc 743b3de2 [GCFrame: 0016f2bc]
Следующее использование !name2ee
чтобы получить метод desc этого метода (это нужно следующей команде):
0:000> !name2ee ConsoleApplication4!ConsoleApplication4.Program.Main
Module: 00282eac
Assembly: ConsoleApplication4.exe
Token: 0600013c
MethodDesc: 00283dbc
Name: ConsoleApplication4.Program.Main(System.String[])
JITTED Code Address: 00320050
Теперь, дамп IL метода:
0:000> !dumpil 00283dbc
ilAddr = 002d4bc4
IL_0000: nop
IL_0001: newobj class [mscorlib]System.Collections.Generic.List`1<?????? ??????n?.::.ctor
IL_0006: stloc.0
IL_0007: br.s IL_001e
IL_0009: nop
IL_000a: ldc.i4 2147483647
IL_000f: newarr System.Single
IL_0014: stloc.1
IL_0015: ldloc.0
IL_0016: ldloc.1
IL_0017: callvirt class [mscorlib]System.Collections.Generic.List`1<?????? ??????N?.::Add
IL_001c: nop
IL_001d: nop
IL_001e: ldc.i4.1
IL_001f: stloc.2
IL_0020: br.s IL_0109
Для сравнения, это мой метод в C#:
static void Main(string[] args)
{
List<float[]> arrays = new List<float[]>();
while (true)
{
float[] f = new float[Int32.MaxValue];
arrays.Add(f);
}
Console.ReadKey();
}
В строке IL_000f видно, что новый массив типа System.Single
создается
Я пошел по этому пути, потому что не могу расшифровать передаваемый аргумент фактическому нативному методу, который создает массив. Если вы бежите kb
в этот момент выдается исключение:
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0016efa4 74502a42 e0434352 00000001 00000005 KERNELBASE!RaiseException+0x58
0016f048 745d55ef 00000000 bc1d0b3d 0016f10c clr!RaiseTheExceptionInternalOnly+0x276
0016f078 7464ae51 bc1d0a7d 0016f150 00000000 clr!UnwindAndContinueRethrowHelperAfterCatch+0x83
0016f118 003200af 00000000 02202480 00000000 clr!JIT_NewArr1+0x1af
0016f138 743b3de2 00720198 0016f198 743c3315 0x3200af
0016f144 743c3315 0016f1dc 0016f188 74502c66 clr!CallDescrWorkerInternal+0x34
...
Ты это видишь clr!JIT_NewArr1
вызывается, который создает одномерный массив. Для этого ему нужны тип и размер. Эти аргументы копируются в ecx
а также edx
соответственно:
0:000> !u 003200AF
...
003200a0 b9e2302a73 mov ecx,offset mscorlib_ni+0x30e2 (732a30e2)
003200a5 baffffff7f mov edx,7FFFFFFFh
003200aa e89121f5ff call 00272240 (JitHelp: CORINFO_HELP_NEWARR_1_VC)
>>> 003200af 8945e8 mov dword ptr [ebp-18h],eax
003200b2 8b45e8 mov eax,dword ptr [ebp-18h]
003200b5 8945f0 mov dword ptr [ebp-10h],eax
...
Как вы видете, ecx
получает 732a30e2
, который каким-то образом отображается на информацию о типе для System.Single
, но я не могу понять, как...