2014-09-16 11 views
7

Tôi có một ngoại lệ OutOfMemoryException và tôi muốn phân tích kích thước và loại mảng sẽ được tạo.Cách xác định loại mảng?

Tôi đã tạo ra một bãi chứa mục đích giới thiệu cho hoàn cảnh đó và tôi có thể nhận được các thông tin sau:

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 
... 

Vì vậy, tôi có thể thấy rằng một mảng mới được tạo ra và kích thước là 7FFFFFFF, đó là 2 tỷ mục. (Vui lòng bỏ qua thực tế là bạn thậm chí không thể tạo một byte [] có kích thước đó trong ứng dụng .NET 32 bit, vì vậy trong ví dụ này, loại có thể không quan trọng chút nào.)

Tôi hiện đã đọc loại mảng nằm trong thanh ghi ECX, nhưng tiếc là mscorlib_ni+0x4102 (78a44102) không phải là rất hữu ích.

Tôi đã thử !mln, !mdt và thậm chí không thực tế !ip2mt, nhưng không ai trong số họ sẽ hiển thị dự kiến ​​byte hoặc byte[] đầu ra. Có cách nào để nhận được loại từ hình ảnh gốc của mscorlib?

+0

Loại mảng thực sự được truyền trong ECX. Tuy nhiên, thay vì mã thông báo siêu dữ liệu thông thường, nó là một 'xử lý cho một mã thông báo siêu dữ liệu'. Điều này được tạo ra bởi JIT. Tôi không biết cách nào để chuyển từ thẻ điều khiển sang mã thông báo siêu dữ liệu gốc. Thay vào đó, kể từ khi IL tồn tại, nó dễ dàng hơn để xem nó để xác định loại mảng. – Dono

Trả lời

3

Một cách để làm điều đó là để đổ IL tương ứng với phương pháp mà các mảng đã được tạo ra trong.

Thứ nhất, sử dụng !clrstack để có được những phương pháp mà bạn đang ở. Trong trường hợp của tôi, tôi đang ở một ứng dụng giả trong phương pháp 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] 

tiếp theo sử dụng !name2ee để có được những desc phương pháp của phương pháp này (lệnh tiếp theo cần nó):

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 

Bây giờ, đổ IL của phương pháp này:

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 

Để so sánh, đây là phương pháp của tôi trong 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(); 
} 

Bạn có thể nhìn thấy trên đường IL_000f rằng một mảng mới của loại System.Single đang được tạo .


Tôi đã đi xuống con đường này vì tôi không thể giải mã đối số được chuyển đến phương thức gốc thực tế tạo mảng. Nếu bạn chạy kb tại điểm ngoại lệ được ném:

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 
... 

Bạn có thể thấy rằng clr!JIT_NewArr1 đang được gọi, mà tạo ra một mảng một chiều. Để làm điều đó, it needs the type and the size. Những lập luận này được sao chép vào ecxedx, tương ứng:

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 
... 

Như bạn thấy, ecx được 732a30e2, mà bằng cách nào đó các bản đồ với các thông tin kiểu cho System.Single, nhưng tôi không thể tìm ra cách ...

Các vấn đề liên quan