none
Wrong file path and line number in Exception stack traces from dynamic code RRS feed

  • Question

  • We are using System.Reflection.Emit to generate code at runtime from source code (yes - as in a compiler). We provide correct symbol information to the ILGenerator with MarkSequencePoint etc, and enable all debug flags on the AssemblyBuilder. The assembly is kept in memory in the same process that compiled it and is executed directly.

    When using the Visual Studio debugger to step through the source for the dynamically generated code it actually works perfectly, and Visual Studio seems to be fully aware of where code comes from in terms of files and line numbers.

    HOWEVER - When exceptions are thrown by the generated code, the System.Exception objects contain stack traces that are completely wrong. They point to other (valid, but wrong) files and line numbers. It gets the class and method name right, but the file and line number pointed to has nothing to do with the code path the exception actually came from.

    The files pointed to are so unrelated it seems it can't be linked to inlining or optimizations. The only pattern I can spot is that it seems to be offset by some files (in an imaginary alphabetically sorted list of source files the assembly was built from). However, this pattern is not 100% consistent, and it seems irrational that this is linked to the source of the problem.

    If i construct a System.Diagnostics.Debug object from the Exception, it contains the same faulty information.

    I am assuming that the .NET runtime uses the same metadata to construct Exception stack traces as the debugger uses for stepping through the code, in which case this behavior is really weird.

    When trying to reproduce the problem with a much simpler project, the error does *not* occur, so unfortunately i have not been able to produce a minimal test case. The real case is quite complex.

    I'm trying to find out if this is a known bug in .NET when dealing with dynamic in-memory assemblies, or if anyone has seen similar problems in other areas.

    Tuesday, January 14, 2014 12:18 PM

Answers

  • Okay, I was NOT able to figure out what was causing the problem nor how to make .NET behave correctly, but at least I was able to find a work-around that might also work for others experiencing the same problem.

    1. As I am generating the CIL bytecode I am building a separate database that maps method names (full path) and IL-offset back to the original file names and line numbers. 

    2. When exceptions are caught I examine the stack trace and use only the `GetMethod()` and `GetILOffset()` information from the stack frame objects. This information from the CLR happens to be correct, even when `GetFileName()` and `GetFileLineNumber()` are wrong.

    3. I then for each stack frame use the Method name and IL offset retrieved from the exception to look up into my generated database to determine actual file name and line number for each stack frame I have information about.

    4. The frames I don't find information about in the database are typically stack frames in precompiled .NET modules, for which the information retrieved from CLR is actually correct. For these frames I use `GetFileName()` and `GetFileLineNumber()` on the stack frame directly.
    Tuesday, January 14, 2014 6:45 PM

All replies

  • Your source code may not be completely recompiling.  I would make a backup copy of the bin folder in the project and then delete the bin folder.  This will cause all you code to recompile.  Then see if you get the same errors.  You can always restore the bin folder. 


    jdweng

    Tuesday, January 14, 2014 1:12 PM
  • Okay, I was NOT able to figure out what was causing the problem nor how to make .NET behave correctly, but at least I was able to find a work-around that might also work for others experiencing the same problem.

    1. As I am generating the CIL bytecode I am building a separate database that maps method names (full path) and IL-offset back to the original file names and line numbers. 

    2. When exceptions are caught I examine the stack trace and use only the `GetMethod()` and `GetILOffset()` information from the stack frame objects. This information from the CLR happens to be correct, even when `GetFileName()` and `GetFileLineNumber()` are wrong.

    3. I then for each stack frame use the Method name and IL offset retrieved from the exception to look up into my generated database to determine actual file name and line number for each stack frame I have information about.

    4. The frames I don't find information about in the database are typically stack frames in precompiled .NET modules, for which the information retrieved from CLR is actually correct. For these frames I use `GetFileName()` and `GetFileLineNumber()` on the stack frame directly.
    Tuesday, January 14, 2014 6:45 PM