1

I would like to know if it is safe to use the following code to determine the name (and possibly more information) about the method or object that called the current executing code:

StackTrace stackTrace = new StackTrace();           // get call stack
StackFrame[] stackFrames = stackTrace.GetFrames();  // get method calls (frames)

More particularly, are there any special/corner cases where accessing the frames would not work or throw exceptions?

I have looked in the MSDN page of StackTrace but found no reference to any possible issues.

svick
  • 236,525
  • 50
  • 385
  • 514
lysergic-acid
  • 19,570
  • 21
  • 109
  • 218
  • 2
    The stacktrace doesn't identify where you've been, it tells you where you are going next. – asawyer Mar 26 '12 at 13:04
  • Sorry for offtopic, but I love the idea of getting into a recursive loop identifying stack trace errors within stack trace handling code. – KingCronus Mar 26 '12 at 13:04
  • @asawyer, thats impossible, how can it know that? – Ash Burlaczenko Mar 26 '12 at 13:12
  • This may be useful: http://stackoverflow.com/questions/171970/how-can-i-find-the-method-that-called-the-current-method – Cronan Mar 26 '12 at 13:24
  • 2
    @liortal If you just need method name and can wait for C# 4.5 you can use [CallerMemberNameAttribute](http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute%28v=vs.110%29.aspx). – brgerner Mar 26 '12 at 13:31
  • @AshBurlaczenko How exactly does your program known which code to run next when the current function ends? – asawyer Mar 26 '12 at 13:37
  • @brgerner Our app uses 3.5. I am away of Caller Info attributes in 4.5 which do just that. – lysergic-acid Mar 26 '12 at 13:47
  • 3
    @AshBulaczenko: No, asawyer is completely correct. A stack trace does not tell you where you came from, it tells you where you are going. **That is the purpose of the stack**. The stack is the mechanism by which the runtime knows *where to go next when the current method is done.* It is a happy accident that most of the time, "where you are going next" and "where you came from" are more or less the same place, but there is no *requirement* that this be the case, and in C# 5 it will *stop* being the case; async code doesn't use the stack to determine where to go next. – Eric Lippert Mar 26 '12 at 14:56
  • 2
    @brgerner: There is no C# 4.5; it will be C# 5. The C# and Visual Basic version numbers do not match the CLR version numbers. – Eric Lippert Mar 26 '12 at 14:58
  • Thanks, Other than inlining, is there any interesting case in which i should beware when counting on the StackTrace to know "my caller" ? – lysergic-acid Mar 26 '12 at 15:08
  • @EricLippert, if I get an exception and look and the 'Stack Trace' I'm pretty sure that tell me what called the code not where the my code is going. How can it know where it's going in a program where the method called is random? – Ash Burlaczenko Mar 26 '12 at 17:28
  • @EricLippert, I've asked the question here, http://stackoverflow.com/questions/9877146/what-is-a-stack-trace, as I didn't want to clog up liortal's question and though your might be able to explain it clearer in an answer box. – Ash Burlaczenko Mar 26 '12 at 17:55
  • @AshBurlaczenko: It tells you *where control is going next when the current method returns*. That is *usually* the same thing as "who called the current method" but **there is no requirement that where you are going next is the same place that you came from.** The runtime is permitted to make optimizations that destroy the information about where you came from if it can do so and still get "where you're going next" correctly. And it does so. Stack traces are *not reliable indicators of where you came from*, only where you are going. – Eric Lippert Mar 26 '12 at 19:09
  • @EricLippert It's a little confusing: You are saying that there's no requirement that you're next stop is where you came from, kinda making this not a reliable indicator of where you are going (or am i misinterpreting?) – lysergic-acid Mar 26 '12 at 19:23
  • 1
    @liortal: Exactly. Suppose for example that the method is *tail recursive*. Say `static bool Contains(Link link, int x) { if (link == null) return false; if (link.Head == x) return true; return Contains(link.Tail, x); }`. Suppose you pass in a linked list with two nodes. You'd expect that after the first and second recursions, the stack trace shows that the caller is `Contains`. But the jit compiler is allowed to realize that *nothing happens after the last call to Contains except that its value is returned.* Therefore the jitter is entirely within its rights to rewrite that as... – Eric Lippert Mar 26 '12 at 20:01
  • ... `static bool Contains(Link link, int x) { while(true) { if (link == null) return false; if (link.Head == x) return true; link = link.Tail; } }`. Now the stack trace after the first and second "recursions" is the original caller, not `Contains`. The jitter can and does perform this optimization on some platforms. – Eric Lippert Mar 26 '12 at 20:04
  • @Eric, @liortal - note that it's not limited to tail _recursion_, the same thing can happen with other tail calls, especially when targeting x64 (where tail calls may be taken even when the `tail.` IL prefix is not emitted, see http://blogs.msdn.com/b/davbr/archive/2007/06/20/tail-call-jit-conditions.aspx). – kvb Mar 26 '12 at 21:30
  • @kvb: Indeed; I intended that to be an example of one way that the stack might not contain the return address of the immediate caller. There are plenty of other scenarios. – Eric Lippert Mar 26 '12 at 21:32

1 Answers1

3

Methods may be inlined by the compiler providing a different view compared to what you expect from directly looking at the code . You can use an attribute to make sure that your method is not inlined:

[MethodImpl(MethodImplOptions.NoInlining)]
public void MyMethod() {
  // Get the stack trace.
}

Otherwise, if MyMethod is inlined the stack trace does not contain the frame for MyMethod which your code may depend on.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • This might not be 100% safe yet ==> http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx – sotto Aug 03 '12 at 07:49