7

I use the following method in my ASP.NET web application to receive the stack trace for an exception:

public static void getStackTraceInfo(System.Diagnostics.StackTrace trace)
{
    for (int i = 0; i < trace.FrameCount; i++)
    {
        int nLine = trace.GetFrame(i).GetFileLineNumber();
        int nCol = trace.GetFrame(i).GetFileColumnNumber();
        string methodName = trace.GetFrame(i).GetMethod().Name;
    }
}

try
{
}
catch(Exception ex)
{
    getStackTraceInfo(new System.Diagnostics.StackTrace(ex, true));
}

It gives me full line/column/method name information if I run it in the Visual Studio 2010 dev environment, but in a production environment on the IIS it returns all 0's and the method name as empty string.

Do I need to do anything special to make it work on IIS as well?

ahmd0
  • 16,633
  • 33
  • 137
  • 233
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 12 '13 at 17:45
  • 1
    This is correct. You're not going to get a stack trace with full debug information (including line numbers) unless the application is compiled in debug mode and the relevant .pdb files are placed in the bin directory in production. Not a recommended practice. – Frazell Thomas Mar 12 '13 at 17:47
  • if your code in "build" in "release" mode , i think you will not get the line number . – aked Mar 12 '13 at 17:48
  • @FrazellThomas: I thought that the absence of the .pdb files could be the reason. Why is uploading them not recommended? – ahmd0 Mar 12 '13 at 17:50
  • @ahmd0 Full debug information, including line numbers and code snippets, can be used by attackers to compromise your application. Instead of having to guess how you're handing various data structures they can see directly. Allowing them to discover holes to exploit a **lot** easier that they otherwise would be able to. – Frazell Thomas Mar 12 '13 at 17:53
  • @FrazellThomas: This information goes into an internal log and is not exposed to the general public. – ahmd0 Mar 12 '13 at 18:12
  • possible duplicate of [C# Exceptions Not Giving Line Numbers](http://stackoverflow.com/questions/2191957/c-sharp-exceptions-not-giving-line-numbers) (as the mechanism used in exceptions is the same) – Justin Mar 12 '13 at 18:18
  • 1
    @ahmd0: You *hope* that the information goes into an internal log and is not exposed to the public. **The fact that you have a log of exceptional failures in the first place is evidence that your program already does not work right**. How do you know that your security measures are working? You are reasoning about the *correctness* of a program subsystem that is only activated *when the program is not working according to its design*. That's a very weak basis from which to reason about correctness. – Eric Lippert Mar 12 '13 at 18:20

1 Answers1

37

It gives me full line/column/method name information if I run it in the Visual Studio 2010 dev environment, but in a production environment on the IIS it returns all 0's and the method name as empty string.

Correct. Read the name of the type carefully; that Diagnostics is important. The types in that namespace were designed for diagnosing problems in a debug environment.

Do I need to do anything special to make it work on IIS as well?

No; you need to not use diagnostic tools in production.

If for some reason you want to use diagnostic tools in a production environment, at a minimum you'll need to push the PDB files to the production environment. This might be a dangerous and foolish thing to do, as we'll see below. I recommend that you do not do so.

Some questions you did not ask:

What tool should I be using to get caller information in a production environment?

If you need to get the line number, etc, of a method call, the tool you probably should be using is the new CallerLineNumber and related attributes in C# 5.0. Here's a good blog on them:

http://blog.slaks.net/2011/10/subtleties-of-c-5s-new-callerlinenumber.html

If you need to get information about the stack trace of an exception, what you see is what you get.

In a debug environment does the StackTrace object provide a guarantee that the stack trace tells me where the current call came from?

No. A stack trace does not tell you where you came from in the first place. A stack trace tells you where you are going next. This is useful because there is often a strong correlation between where you came from and where you're going next; usually you're going back to where you came from.

This is not always true though. The CLR can sometimes figure out where to go next without knowing where you came from, in which case the stack trace doesn't contain the information you need.

For example, tail call optimizations can remove frames from the stack. Inlining optimizations can make a call to a method look like part of the calling method. Asynchronous workflows in C# 5 completely divorce "where you came from" and "where you're going next"; the stack trace of an asynchronous method resumed after an await tells you where you are going after the next await, not how you got into the method before the first await.

Stack traces are unreliable, so do not rely on them. Use them only as a diagnostic aid.

Why is it particularly dangerous to expose diagnostic information in ASP?

Because attackers will attempt to cause your server to fail by throwing "exceptional" inputs at it. If that brings the server down, great, the attackers will be happy. If it keeps the server up but leaks information about your source code to the attacker, even better. Now they have more information to use to mount a more sophisticated attack.

ASP servers should profer up as little diagnostic information as possible in a production environment. The less debug information you have in that production environment, the less likely you are to make a mistake and expose your implementation details to an attacker.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Good point, except this remark `stack trace does not tell you where you came from`. It tells you exactly that. True, some procedures may modify it, but that's too unusual for your run of the mill code. As for the dangers of exposing all this debugger info to the general public -- I totally agree. All this information goes into an internal log that is not exposed. – ahmd0 Mar 12 '13 at 18:10
  • 18
    @ahmd0: It is amazing the resistance I get when I tell people the truth about stack traces. The stack trace contains the *return address*, which need not be the address of the *caller*. Most of the time it is, but it does not have to be and there are situations in which it is not. Remember, the purpose of the stack is the *reification of continuation*, and continuation is by definition information about *the future*, not *the past*. If you can sometimes deduce information about the past from the continuation, great, but that's not its *purpose*, so you cannot rely on it. – Eric Lippert Mar 12 '13 at 18:17
  • 2
    There is also of course no requirement that continuation be reified by a stack at all. As I mentioned above, continuation of an asynchronous task is reified by the combination of a delegate and a context; there's no stack involved, and therefore knowing the continuation of a task tells you nothing whatsoever about how that task was begun. – Eric Lippert Mar 12 '13 at 18:18
  • 3
    @ahmd0: Many simple stack traces do *happen* to have where you came from, if that's the same as where you're going. Eric mentioned that `async` code in particular separates these two; [this MSDN article](http://msdn.microsoft.com/en-us/magazine/jj891052.aspx) goes into more detail. – Stephen Cleary Mar 12 '13 at 18:20
  • @StephenCleary: I had not seen that article yet; it's really good. Thanks for the link! – Eric Lippert Mar 12 '13 at 18:27
  • It's possibly because of the *reification of continuation*, make people think stack trace tells that where the current call came from. – Ken Kin Mar 12 '13 at 21:39
  • 4
    @KenKin: No, I think it's because most people are *taught* that the stack trace "tells you where you came from", and because it is *true* in 99.99% of the code most developers see, that they believe it. It can be profoundly unsettling to have the realization that the stack trace only tells you where you came from *because you're going back there*, and not *because that's its by-design purpose*. – Eric Lippert Mar 12 '13 at 21:54
  • One possibility is, to have some syntax sugar that whenever a `Task` being created, have the current stack trace stored inside the `Task` object. Also, if the current thread running code for a `Task`, have this information recorded in a thread local variable. In this way, the debugger can present more useful information about where the tasks came from and to return to. – Earth Engine Aug 06 '14 at 01:59
  • I have similar facility for custom `IDisposable`s to track objects that were not `Dispose`d properly. And this gives me really useful debugging information! – Earth Engine Aug 06 '14 at 02:02
  • @EricLippert: very interesting, so there is no way to find - in debug - where a method comes from? – Revious Sep 01 '16 at 16:26
  • 1
    @Revious: There is no *requirement* that the system stores information about where control came from *if that information is not necessary for correct operation of the program*. But as a debugging aid, there are many ways you can configure the debugger to keep track of the historical flow of control. Visual Studio has lots of control flow tracking features in the debugger; check them out! In particular, note the article linked by Stephen above. – Eric Lippert Sep 01 '16 at 17:29