2013-12-10 3 views
4

Иногда, когда я получаю отчет о сбоях из приложения, в трассировке стека отсутствует метод. Я не думаю, что следующий код будет воспроизводить его, но, скажем так, для справки мы имеем это:Исключительная трассировка стека Отсутствующие элементы

using System.IO; 
using System; 
using System.Collections.Generic; 

class Program 
{ 
    static List<int> stuff; 
    static void Main() 
    { 
     stuff = new List<int>(); 
     int result = Foo(); 
    } 

    static int Foo(){ 
     return Bar(5); 
    } 

    static int Bar(int value){ 
     return stuff[value]; 
    } 
} 

Когда System.Collections.Generic.List'1.get_Item(Int32 index) бросает System.ArgumentOutOfRangeException, трассировки стека не хватает Foo(). Ради этого аргумента компилятор не оптимизировал код, так как декомпилятор показывает, что он не был выровнен. Кто-нибудь знает, что может вызвать это (кроме компилятора в подкладке)?

Редактировать: Чтобы уточнить, приложение не находится в режиме отладки при выполнении Stack Trace.

+5

Плохая обработка исключений вызовет это. 'try {} catch (Exception ex) {throw ex;}' –

+0

Я все еще уверен, что функция была встроена. Часто инкрустация не появляется в IL/de-компиляторе, поскольку она выполняется движком JIT. –

+0

Это может быть возможно. Но это очень раздражает, когда на трассе отсутствуют несколько методов и свойств (например, 5 или около того). Итак, нет способа включить это в трассировку стека? Это облом ... –

ответ

7

TL; DR: Методы встроены JIT не компилятором, тогда вы можете увидеть его только в ASM разборке, а не в MSIL разборка.

Скомпилируем код youe в режиме отладки, теперь давайте декомпилируем MSIL.

И результат кажется прекрасным:

namespace ConsoleTests 
{ 
    using System; 
    using System.Collections.Generic; 

    internal class Program 
    { 
     private static List<int> stuff; 

     private static int Bar(int value) 
     { 
      return stuff[value]; 
     } 

     private static int Foo() 
     { 
      return Bar(5); 
     } 

     private static void Main() 
     { 
      stuff = new List<int>(); 
      int num = Foo(); 
     } 
    } 
} 

Также стек вызовов завершена:

Необработанное исключение: System.ArgumentOutOfRangeException: Индекс находился вне диапазона. Должен быть неотрицательным и меньше размера коллекции. Имя Параметр: Индекс

в System.ThrowHelper.ThrowArgumentOutOfRangeException (ExceptionArgument аргумент, ExceptionResource ресурс)

на System.Collections.Generic.List`1.get_Item (индекс Int32)

на ConsoleTests.Program .Bar (значение Int32) в C: \ Users \ Some1Pr0 \ documents \ visual studio 2015 \ Projects \ ConsoleTests \ ConsoleTests \ Program.cs: строка 40

at ConsoleTests.Program.Foo() в C: \ Users \ Some1Pr0 \ documents \ visual studio 2015 \ Projects \ ConsoleTests \ ConsoleTests \ Program.cs: строка 35

at ConsoleTests.Program.Main() в C: \ Users \ Some1Pr0 \ documents \ visual studio 2015 \ Projects \ ConsoleTests \ ConsoleTests \ Program.CS: линия 30

Теперь давайте компилировать в выпуске:

Теперь мы видим, что стек вызовов не является полным:

Необработанное исключение: System.ArgumentOutOfRangeException: Индекс находился вне диапазона , Должен быть неотрицательным и меньше размера коллекции. Имя параметра: индекс

в System.ThrowHelper.ThrowArgumentOutOfRangeException (ExceptionArgument аргумент, ExceptionResource ресурс)

в ConsoleTests.Program.Main() в C: \ Users \ Some1Pr0 \ Documents \ Visual Studio 2015 \ Projects \ ConsoleTests \ ConsoleTests \ Program.cs: линия 30

Кроме того, отладчик VS2015 не может уйти в Foo.

Давайте проверять MSIL:

namespace ConsoleTests 
{ 
    using System; 
    using System.Collections.Generic; 

    internal class Program 
    { 
     private static List<int> stuff; 

     private static int Bar(int value) 
     { 
      return stuff[value]; 
     } 

     private static int Foo() 
     { 
      return Bar(5); 
     } 

     private static void Main() 
     { 
      stuff = new List<int>(); 
      Foo(); 
     } 
    } 
} 

Видимо код выглядит так же, так что давайте сделаем шаг глубже и проверить код JITTEDassembly.

Если мы посмотрим на разборки отладки версии мы увидим, что весь код там, включая полные JITTED метод:

00007FFDD8AF4722 56     push  rsi 
00007FFDD8AF4723 48 83 EC 40   sub   rsp,40h 
00007FFDD8AF4727 48 8B EC    mov   rbp,rsp 
00007FFDD8AF472A 48 8D 7D 24   lea   rdi,[rbp+24h] 
00007FFDD8AF472E B9 07 00 00 00  mov   ecx,7 
00007FFDD8AF4733 33 C0    xor   eax,eax 
00007FFDD8AF4735 F3 AB    rep stos dword ptr [rdi] 
00007FFDD8AF4737 48 B8 00 4F B3 D8 FD 7F 00 00 mov   rax,7FFDD8B34F00h 
00007FFDD8AF4741 83 38 00    cmp   dword ptr [rax],0 
00007FFDD8AF4744 74 05    je   00007FFDD8AF474B 
00007FFDD8AF4746 E8 B1 17 AB 5F  call  00007FFE385A5EFC 
00007FFDD8AF474B 90     nop 
    29:    stuff = new List<int>(); 
00007FFDD8AF474C 48 B9 28 F1 1F 37 FE 7F 00 00 mov   rcx,7FFE371FF128h 
00007FFDD8AF4756 E8 65 01 63 5F  call  00007FFE381248C0 
00007FFDD8AF475B 48 89 45 28   mov   qword ptr [rbp+28h],rax 
00007FFDD8AF475F 48 8B 4D 28   mov   rcx,qword ptr [rbp+28h] 
00007FFDD8AF4763 E8 E8 0E E7 5E  call  00007FFE37965650 
00007FFDD8AF4768 48 B9 70 85 6C D9 63 00 00 00 mov   rcx,63D96C8570h 
00007FFDD8AF4772 48 8B 55 28   mov   rdx,qword ptr [rbp+28h] 
00007FFDD8AF4776 E8 85 CD 62 5F  call  00007FFE38121500 
    30:    int result = Foo(); 
00007FFDD8AF477B E8 F0 C7 FF FF  call  00007FFDD8AF0F70 
00007FFDD8AF4780 89 45 24    mov   dword ptr [rbp+24h],eax 
00007FFDD8AF4783 8B 45 24    mov   eax,dword ptr [rbp+24h] 
00007FFDD8AF4786 89 45 34    mov   dword ptr [rbp+34h],eax 
    31:   } 
00007FFDD8AF4789 90     nop 
00007FFDD8AF478A 48 8D 65 40   lea   rsp,[rbp+40h] 
00007FFDD8AF478E 5E     pop   rsi 
00007FFDD8AF478F 5F     pop   rdi 
00007FFDD8AF4790 5D     pop   rbp 
00007FFDD8AF4791 C3     ret 




    34:   { 
00007FFDD8AF47B0 55     push  rbp 
00007FFDD8AF47B1 57     push  rdi 
00007FFDD8AF47B2 56     push  rsi 
00007FFDD8AF47B3 48 83 EC 30   sub   rsp,30h 
00007FFDD8AF47B7 48 8B EC    mov   rbp,rsp 
00007FFDD8AF47BA 48 8D 7D 20   lea   rdi,[rbp+20h] 
00007FFDD8AF47BE B9 04 00 00 00  mov   ecx,4 
00007FFDD8AF47C3 33 C0    xor   eax,eax 
00007FFDD8AF47C5 F3 AB    rep stos dword ptr [rdi] 
00007FFDD8AF47C7 48 B8 00 4F B3 D8 FD 7F 00 00 mov   rax,7FFDD8B34F00h 
00007FFDD8AF47D1 83 38 00    cmp   dword ptr [rax],0 
00007FFDD8AF47D4 74 05    je   00007FFDD8AF47DB 
00007FFDD8AF47D6 E8 21 17 AB 5F  call  00007FFE385A5EFC 
00007FFDD8AF47DB 90     nop 
    35:    return Bar(5); 
00007FFDD8AF47DC B9 05 00 00 00  mov   ecx,5 
00007FFDD8AF47E1 E8 92 C7 FF FF  call  00007FFDD8AF0F78 
00007FFDD8AF47E6 89 45 20    mov   dword ptr [rbp+20h],eax 
00007FFDD8AF47E9 8B 45 20    mov   eax,dword ptr [rbp+20h] 
00007FFDD8AF47EC 89 45 24    mov   dword ptr [rbp+24h],eax 
00007FFDD8AF47EF 90     nop 
00007FFDD8AF47F0 EB 00    jmp   00007FFDD8AF47F2 
    36:   } 
00007FFDD8AF47F2 8B 45 24    mov   eax,dword ptr [rbp+24h] 
00007FFDD8AF47F5 48 8D 65 30   lea   rsp,[rbp+30h] 
00007FFDD8AF47F9 5E     pop   rsi 
00007FFDD8AF47FA 5F     pop   rdi 
00007FFDD8AF47FB 5D     pop   rbp 
00007FFDD8AF47FC C3     ret 


    34:   { 
00007FFDD8AF47B2 56     push  rsi 
00007FFDD8AF47B3 48 83 EC 30   sub   rsp,30h 
00007FFDD8AF47B7 48 8B EC    mov   rbp,rsp 
00007FFDD8AF47BA 48 8D 7D 20   lea   rdi,[rbp+20h] 
00007FFDD8AF47BE B9 04 00 00 00  mov   ecx,4 
00007FFDD8AF47C3 33 C0    xor   eax,eax 
00007FFDD8AF47C5 F3 AB    rep stos dword ptr [rdi] 
00007FFDD8AF47C7 48 B8 00 4F B3 D8 FD 7F 00 00 mov   rax,7FFDD8B34F00h 
00007FFDD8AF47D1 83 38 00    cmp   dword ptr [rax],0 
00007FFDD8AF47D4 74 05    je   00007FFDD8AF47DB 
00007FFDD8AF47D6 E8 21 17 AB 5F  call  00007FFE385A5EFC 
00007FFDD8AF47DB 90     nop 
    35:    return Bar(5); 
00007FFDD8AF47DC B9 05 00 00 00  mov   ecx,5 
00007FFDD8AF47E1 E8 92 C7 FF FF  call  00007FFDD8AF0F78 
00007FFDD8AF47E6 89 45 20    mov   dword ptr [rbp+20h],eax 
00007FFDD8AF47E9 8B 45 20    mov   eax,dword ptr [rbp+20h] 
00007FFDD8AF47EC 89 45 24    mov   dword ptr [rbp+24h],eax 
00007FFDD8AF47EF 90     nop 
00007FFDD8AF47F0 EB 00    jmp   00007FFDD8AF47F2 
    36:   } 
00007FFDD8AF47F2 8B 45 24    mov   eax,dword ptr [rbp+24h] 
00007FFDD8AF47F5 48 8D 65 30   lea   rsp,[rbp+30h] 
00007FFDD8AF47F9 5E     pop   rsi 
00007FFDD8AF47FA 5F     pop   rdi 
00007FFDD8AF47FB 5D     pop   rbp 
00007FFDD8AF47FC C3     ret 


    39:   { 
00007FFDD8AF4820 55     push  rbp 
00007FFDD8AF4821 57     push  rdi 
00007FFDD8AF4822 56     push  rsi 
00007FFDD8AF4823 48 83 EC 30   sub   rsp,30h 
00007FFDD8AF4827 48 8B EC    mov   rbp,rsp 
00007FFDD8AF482A 48 8B F1    mov   rsi,rcx 
00007FFDD8AF482D 48 8D 7D 20   lea   rdi,[rbp+20h] 
00007FFDD8AF4831 B9 04 00 00 00  mov   ecx,4 
00007FFDD8AF4836 33 C0    xor   eax,eax 
00007FFDD8AF4838 F3 AB    rep stos dword ptr [rdi] 
00007FFDD8AF483A 48 8B CE    mov   rcx,rsi 
00007FFDD8AF483D 89 4D 50    mov   dword ptr [rbp+50h],ecx 
00007FFDD8AF4840 48 B8 00 4F B3 D8 FD 7F 00 00 mov   rax,7FFDD8B34F00h 
00007FFDD8AF484A 83 38 00    cmp   dword ptr [rax],0 
00007FFDD8AF484D 74 05    je   00007FFDD8AF4854 
00007FFDD8AF484F E8 A8 16 AB 5F  call  00007FFE385A5EFC 
00007FFDD8AF4854 90     nop 
    40:    return stuff[value]; 
00007FFDD8AF4855 48 B9 70 85 6C D9 63 00 00 00 mov   rcx,63D96C8570h 
00007FFDD8AF485F 48 8B 09    mov   rcx,qword ptr [rcx] 
00007FFDD8AF4862 8B 55 50    mov   edx,dword ptr [rbp+50h] 
00007FFDD8AF4865 39 09    cmp   dword ptr [rcx],ecx 
00007FFDD8AF4867 E8 94 0C E7 5E  call  00007FFE37965500 
00007FFDD8AF486C 89 45 20    mov   dword ptr [rbp+20h],eax 
00007FFDD8AF486F 8B 45 20    mov   eax,dword ptr [rbp+20h] 
00007FFDD8AF4872 89 45 24    mov   dword ptr [rbp+24h],eax 
00007FFDD8AF4875 90     nop 
00007FFDD8AF4876 EB 00    jmp   00007FFDD8AF4878 
    41:   } 
00007FFDD8AF4878 8B 45 24    mov   eax,dword ptr [rbp+24h] 
00007FFDD8AF487B 48 8D 65 30   lea   rsp,[rbp+30h] 
00007FFDD8AF487F 5E     pop   rsi 
00007FFDD8AF4880 5F     pop   rdi 
00007FFDD8AF4881 5D     pop   rbp 
00007FFDD8AF4882 C3     ret 

Но когда мы проверить релиз версии мы можем увидеть что это действительно встраиваемыми (по JIT - не компилятором) и мы можем видеть, связанные проверки списка индексатор внутри метода Main:

29:    stuff = new List<int>(); 
00007FFDD8AD4102 83 EC 20    sub   esp,20h 
00007FFDD8AD4105 48 B9 28 F1 1F 37 FE 7F 00 00 mov   rcx,7FFE371FF128h 
00007FFDD8AD410F E8 AC 07 65 5F  call  00007FFE381248C0 
00007FFDD8AD4114 48 8B F0    mov   rsi,rax 
00007FFDD8AD4117 B9 01 00 00 00  mov   ecx,1 
00007FFDD8AD411C BA 43 00 00 00  mov   edx,43h 
00007FFDD8AD4121 E8 46 0A 7B 5F  call  00007FFE38284B6C 
00007FFDD8AD4126 48 BA 60 89 E1 2D 69 00 00 00 mov   rdx,692DE18960h 
00007FFDD8AD4130 48 8B 12    mov   rdx,qword ptr [rdx] 
00007FFDD8AD4133 48 8D 4E 08   lea   rcx,[rsi+8] 
00007FFDD8AD4137 E8 F4 D3 64 5F  call  00007FFE38121530 
00007FFDD8AD413C 48 B9 60 85 E1 2D 69 00 00 00 mov   rcx,692DE18560h 
00007FFDD8AD4146 48 8B D6    mov   rdx,rsi 
00007FFDD8AD4149 E8 B2 D3 64 5F  call  00007FFE38121500 
    30:    int result = Foo(); 
00007FFDD8AD414E 48 B9 60 85 E1 2D 69 00 00 00 mov   rcx,692DE18560h 
00007FFDD8AD4158 48 8B 31    mov   rsi,qword ptr [rcx] 
00007FFDD8AD415B 83 7E 18 05   cmp   dword ptr [rsi+18h],5 
//------------------------------------------------------------------------- 
00007FFDD8AD415F 77 0F    ja   00007FFDD8AD4170 //BOUND CHECK!!!!! 
//------------------------------------------------------------------------- 
00007FFDD8AD4161 B9 0D 00 00 00  mov   ecx,0Dh 
00007FFDD8AD4166 BA 16 00 00 00  mov   edx,16h 
00007FFDD8AD416B E8 A0 2C D2 5E  call  00007FFE377F6E10 //EXCEPTION 
00007FFDD8AD4170 48 8B 46 08   mov   rax,qword ptr [rsi+8] 
00007FFDD8AD4174 83 78 08 05   cmp   dword ptr [rax+8],5 
00007FFDD8AD4178 76 09    jbe   00007FFDD8AD4183 
00007FFDD8AD417A 8B 40 24    mov   eax,dword ptr [rax+24h] 
00007FFDD8AD417D 48 83 C4 20   add   rsp,20h 
00007FFDD8AD4181 5E     pop   rsi 
00007FFDD8AD4182 C3     ret 
00007FFDD8AD4183 E8 50 45 AD 5F  call  00007FFE385A86D8 
00007FFDD8AD4188 CC     int   3 
1

У меня была аналогичная проблема при выполнении некоторых тестов для регистрации исключений.

Как сказал Джон Гибб, это вставка. Виновные за пропущенные шаги в StackTrace были компилятором, который был встраивание моих методов:

отладки релиз

ClassLibrary1.Class2.ThrowAgain() 
ClassLibrary1.Class2.ThrowSomething() 
WindowsFormsApplication1.Program.Main(String[] args) 

at WindowsFormsApplication1.Program.Main(String[] args) 
Смежные вопросы