Search code examples
c#stack-traceunhandled-exception

More specific exception location in stacktrace without pdb file


In an application one should always try their best to ensure code is fully tested, and is written in such a way that malformed input or actions are handled gracefully.

We are only human though and mistakes creep in, in a last ditch effort to improve the user-experience instead of unceremoniously crashing to the desktop it is common to catch unhanded exceptions, throw a message to the user and record some fault information.

Usually a PDB is not distributed with the finished program and as such a system trace will not contain line numbers which can make it difficult to locate the offending line that threw the error.

Take the following example program (a .net console app for simplicity)

using System;

namespace ExceptionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Just in case we forget to catch something properly.
            System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;

            Console.WriteLine(DoStuff(10));

            Console.ReadKey();
        }

        static int DoStuff(int parameter)
        {
            int[] data = { 1, 2, 3, 4, 5, 6 };

            int value = data[parameter]; // Improperly checked code

            return value;
        }

        static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine(e.ExceptionObject.ToString());
            Console.WriteLine("Press Enter to continue");
            Console.ReadLine();
            Environment.Exit(1);
        }
    }
}

If that gets run without .pdb file present it will dutifully catch the error and report on it.

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at ExceptionTest.Program.DoStuff(Int32 parameter)
   at ExceptionTest.Program.Main(String[] args)
Press Enter to continue

Is there any way to include the point in user code at which the fault occured or is this simply not present in the executable (obviously some symbol information is included as we can see the DoStuff function name.

For example is there any way I could log int value = data[parameter]; in addition to the stack trace.


Solution

  • What you see in this call stack without PDBs is available because your C# code is provided as Intermediate Language (IL).

    Think like this: everything you could do via reflection (e.g. asking for classes and asking classes for their methods) is also available in the IL code and thus can be part of the stack trace.

    But still, the IL code is optimized in a release build and e.g. unused variables can be removed.

    Is there any way to include the point

    No. That information is in the PDBs. The idea is that you build the PDBs even for a release build and store them in a symbol server at least for the versions that you ship to customers.

    I would also not just catch an exception and show information to the user or save it in a log file. Instead, create a crash dump file (.DMP) that you can analyze on your PC using the PDBs you have stored for exactly that purpose.