views:

851

answers:

7

I thought .Net code gets compiled into MSIL, so I always wondered how do Yellow Screens produce the faulty code. If it's executing the compiled code, how is the compiler able to produce code from the source files in the error message?

Feel free to edit this question/title, I know it doesn't really make sense.

+3  A: 

I believe the pdb files that are output when you do a debug build contain a reference to the location of the source code files.

John Christensen
The YSOD will still show the stacktrace without the PDB files.
Greg Hurlman
A: 

I think this is down to the debug information that can be included with the compiled assemblies..(although I could definately be wrong)

Rob Cooper
A: 

I believe the information that maps the source to the MSIL is stored in the PDB file. If this is not present then that mapping won't happen.

It is this lookup that makes an exception such a expensive operation ("exceptions are for exceptional situations").

Nick
+6  A: 

A .Net assembly is compiled with metadata about the bytecode included that allows easy decompilation of the code - that's how tools like .Net Reflector work. The PDB files are debug symbols only - the difference in the Yellow Screen Of Death is that you'll get line numbers in the stack trace.

In other words, you'd get the code, even if the PDB files were missing.

Greg Hurlman
+2  A: 

like this. i've made a few changes, but it's pretty close to exactly what ms is doing.

// reverse the stack
private static Stack<Exception> GenerateExceptionStack(Exception exception)
{
    var exceptionStack = new Stack<Exception>();

    // create exception stack
    for (Exception e = exception; e != null; e = e.InnerException)
    {
        exceptionStack.Push(e);
    }

    return exceptionStack;
}

// render stack
private static string GenerateFormattedStackTrace(Stack<Exception> exceptionStack)
{
    StringBuilder trace = new StringBuilder();

    try
    {
        // loop through exception stack
        while (exceptionStack.Count != 0)
        {
            trace.Append("\r\n");

            // render exception type and message
            Exception ex = exceptionStack.Pop();
            trace.Append("[" + ex.GetType().Name);
            if (!string.IsNullOrEmpty(ex.Message))
            {
                trace.Append(":" + ex.Message);
            }
            trace.Append("]\r\n");

            // Load stack trace
            StackTrace stackTrace = new StackTrace(ex, true);
            for (int frame = 0; frame < stackTrace.FrameCount; frame++)
            {
                StackFrame stackFrame = stackTrace.GetFrame(frame);
                MethodBase method = stackFrame.GetMethod();
                Type declaringType = method.DeclaringType;
                string declaringNamespace = "";

                // get declaring type information
                if (declaringType != null)
                {
                    declaringNamespace = declaringType.Namespace ?? "";
                }

                // add namespace
                if (!string.IsNullOrEmpty(declaringNamespace))
                {
                    declaringNamespace += ".";
                }

                // add method
                if (declaringType == null)
                {
                    trace.Append(" " + method.Name + "(");
                }
                else
                {
                    trace.Append(" " + declaringNamespace + declaringType.Name + "." + method.Name + "(");
                }

                // get parameter information
                ParameterInfo[] parameters = method.GetParameters();
                for (int paramIndex = 0; paramIndex < parameters.Length; paramIndex++)
                {
                    trace.Append(((paramIndex != 0) ? "," : "") + parameters[paramIndex].ParameterType.Name + " " + parameters[paramIndex].Name);
                }
                trace.Append(")");


                // get information
                string fileName = stackFrame.GetFileName() ?? "";

                if (!string.IsNullOrEmpty(fileName))
                {
                    trace.Append(string.Concat(new object[] { " in ", fileName, ":", stackFrame.GetFileLineNumber() }));
                }
                else
                {
                    trace.Append(" + " + stackFrame.GetNativeOffset());
                }

                trace.Append("\r\n");
            }
        }
    }
    catch
    {
    }

    if (trace.Length == 0)
    {
        trace.Append("[stack trace unavailable]");
    }

    // return html safe stack trace
    return HttpUtility.HtmlEncode(trace.ToString()).Replace(Environment.NewLine, "<br>");
}
Darren Kopp
+4  A: 
Kevin
scroll down please, I want to know stackoverflow.com's classes
Vlagged
A: 

Jeff is not doing well showing the source to the public. Even the "beta" public. He should put up custom error pages (and ofcourse, log the errors afaik he is..)

Andrei Rinea