0

Sometimes in managed calls stack, inspite any method call I get InlinedCallFrame. What does this exactly mean?

0024e6dc 6fe1e38f Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(Int32, IntPtr, IntPtr)  
0024e6fc 6fa64c29 Microsoft.Win32.SystemEvents.WindowProc(IntPtr, Int32, IntPtr, IntPtr)  
0024e700 000a1104 [InlinedCallFrame: 0024e700]   
0024e8d8 6e378d5e System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)  
0024e974 6e3789c7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)  
0024e9c8 6e378811 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)  
palm snow
  • 2,392
  • 4
  • 29
  • 49
  • This should not happen if you started the process under the debugger. You attached to the process, correct? – leppie Dec 02 '11 at 14:10
  • i am looking a dump file – palm snow Dec 02 '11 at 14:13
  • I could be wrong, but this might refer to a delegate or a native function pointer. Personally, I would not worry about it, it seems like an implementation detail. – leppie Dec 02 '11 at 15:18
  • If its a system API its a different case. But if its my application code, I would like to know about it as this provides me traceability in code as to why a particular method is been called – palm snow Dec 02 '11 at 15:47
  • If you look around it, it is probably not. Stuff like that happens when you run apps normally. Unless you can pinpoint the problem to this `inlinedframe` I would not worry. – leppie Dec 04 '11 at 18:06

1 Answers1

0

tl;dr - It is a deep implementation detail - it can be ignored by a typical .NET developer. It is an object that the runtime leaves on the stack to help with stack walking.

Context:

In the early days of computing, there is no exception handling and there is no garbage collection. So there isn't a hard requirement for stacks to be walkable. Therefore, in general, the stack is not walkable.

Technically, the debuggers need them. The debuggers pulled off magic to achieve it. I will skip the actual mechanism here.

To support exception, garbage collection, and debugging, the CLR has to make sure that all managed frames are walkable. To do that, the JIT generates code that is described so that the stack walker knows how to unwind the individual managed frames.

Once in a while, managed code needs to call into some code written in C++. It could be because we are doing a PInvoke, but it could also be various other reasons, for example, when we need to do a GC, or we are doing reflection, etc. In those cases, the stack will have some C++ code on it, and there is no guarantee that c++ code produces stack frames that are walkable, so we have a problem.

Solution:

That's why we have these Frame objects. These Frame objects are meant to solve that problem.

The naming is a bit unfortunate. We have stack frames and we have Frame objects. Note the capital F in Frame, that is how we differentiate them.

A Frame object is allocated on the stack, it is a linked list so every Frame can have a parent Frame (or FRAME_TOP if we don't have one), and the top Frame can be accessed through a thread static. Together, these form a separate linked list that is side-by-side with the actual stack.

With the two, now we can walk them side by side, and interleave them by their addresses. Remember stack pointer values decrease as we make function calls. So from the callee to caller, the stack pointer should always increase, so we know exactly how to interleave them. More interestingly, these Frame objects are responsible for skipping through the c++ frames, so we know exactly how to walk the whole stack for managed frames.

Caveat - do not attempt to debug frame chain creation by setting breakpoints on constructors. Some Frame objects are directly placed on the stack by assembly stubs or jitted code.

Ever since x64, the platform application binary interface is designed so that the stack is always walkable, at least for Windows. So helping the stack walker is technically no longer needed. But since x86 has to be supported, and it is a nice thing to have that we can skip through the native frames, this separate chain of Frame objects stayed.

Technically, it is a bit confusing that !clrstack show them there as a row just like the others. That line does NOT represent a function call. Instead, it is a special object that happens to be on the stack, just like your arguments or locals. It might be useful for a .NET runtime developer to debug what's gone wrong in the stack walker, but it is almost useless for developers writing .NET code.

Feel free to learn more about CLR stack walking here

Andrew Au
  • 812
  • 7
  • 18