Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception Stack Trace Missing Items

Sometimes, when I get a crash report from an application, a method is missing in the stack trace. I don't think the following code will reproduce it, but let's say, for reference we have this:

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];
    }
}

When System.Collections.Generic.List'1.get_Item(Int32 index) throws a System.ArgumentOutOfRangeException, the stack trace is missing Foo(). For the sake of this argument, the compiler did not optimize the code since the de-compiler shows that it was not in-lined. Does anyone know what would cause this (other than compiler in-lining)?

Edit: To clarify, the application is not in debug mode when the Stack Trace is made.

like image 710
BrainStorm.exe Avatar asked Dec 10 '13 21:12

BrainStorm.exe


People also ask

Can exception stack trace null?

Yes. If you create a new Exception() and don't throw it, every property except Data and Message will be null.

What is stack trace exception?

A trace of the method calls is called a stack trace. The stack trace listing provides a way to follow the call stack to the line number in the method where the exception occurs. The StackTrace property returns the frames of the call stack that originate at the location where the exception was thrown.

What causes a stack trace error?

Whenever a certain function call throws an error, you'll have a collection of function calls that lead up to the call that caused the particular problem. This is due to the LIFO behavior of the collection that keeps track of underlying, previous function calls. This also implies that a stack trace is printed top-down.


1 Answers

TL;DR: The methods are inlined by the JIT not by the compiler, then you can see it only in ASM disassembly, not in MSIL disassembly.

Let's compile youe code in debug mode, now let's decompile the MSIL.

And the result seems fine:

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();
        }
    }
}

Also the call stack is complete:

Unhandled Exception: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)

at System.Collections.Generic.List`1.get_Item(Int32 index)

at ConsoleTests.Program.Bar(Int32 value) in C:\Users\Some1Pr0\documents\visual studio 2015\Projects\ConsoleTests\ConsoleTests\Program.cs:line 40

at ConsoleTests.Program.Foo() in C:\Users\Some1Pr0\documents\visual studio 2015\Projects\ConsoleTests\ConsoleTests\Program.cs:line 35

at ConsoleTests.Program.Main() in C:\Users\Some1Pr0\documents\visual studio 2015\Projects\ConsoleTests\ConsoleTests\Program.cs:line 30

Now let's compile in release:

Now we can see that the call stack is not complete:

Unhandled Exception: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)

at ConsoleTests.Program.Main() in C:\Users\Some1Pr0\documents\visual studio 2015\Projects\ConsoleTests\ConsoleTests\Program.cs:line 30

Also, the debugger of VS2015 cannot step into Foo.

Let's inspect the 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();
        }
    }
}

Apparently the code looks the same, so let's take a step deeper and inspect the JITTED assembly code.

If we look at the disassembly of the debug version we will see that the whole code is there including the full JITTED methods:

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  

But when we inspect the release version we can see that it was indeed inlined (by the JIT - not by the compiler) and we can see the bound checks of the list indexer inside the Main method:

    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  
like image 54
Tamir Vered Avatar answered Sep 20 '22 08:09

Tamir Vered