0

Is there a way to catch a regular C++ exception and get the CONTEXT object for it, so we can walk the stack and get a backtrace without resorting to __try and __except phrases?

UPDATE: While I understand how to setup and use unhandled exception filters, I really wish to handle those exceptions with try..catch and get a stack trace without going to the top-level of the thread.

Lothar
  • 860
  • 6
  • 21
  • Sadly, there is no way. C++ exceptions aren't stack trace friendly. – Ajay Apr 11 '16 at 14:46
  • Walking the stack sounds like fun, but it's really hardly ever useful. Set up an unhandled exception filter, and write a minidump instead. The exception filter comes with an [EXCEPTION_POINTERS](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679331.aspx) structure, ready to be written to a dump, and read back into a debugger. @Ajay: C++ exceptions **are** SEH exceptions (as implemented by VS anyway). What specifically makes them *"not stack trace friendly"*? – IInspectable Apr 11 '16 at 14:52
  • @IInspectable If C++ exceptions *are* SEH exceptions can I has CONTEXT? Because you *can* get those for SEH exceptions – Lothar Apr 11 '16 at 15:02
  • 1
    @IInspectable, No C++ exceptions are not SEH. Try throwing a C++ object deep down a call stack, and see if you can trace it to the function that has thrown it. A `__try` and `__except` statement can **never** catch a C++ exception. However, with a compiler flag, a C++ exception handler can handle both SEH and C++. Also, you cannot have `__try` (SEH) and `try` (C++) in same function. – Ajay Apr 11 '16 at 16:34
  • Minidumps are second step, what if you can stack-trace and log it, so that client can immediately send the log, and developer start looking for bug? Instead of waiting for mini-dump (mega-dumps) to reach at developer, figure out what PDBs went, which exact source code was used and so on. – Ajay Apr 11 '16 at 16:36
  • @Ajay: If a customer can send a stack trace, then that customer can send a minidump as well. You cannot find but the most trivial bugs by looking at a stack trace either. Constructing a meaningful stack trace requires that you ship .pdb's alongside your application as well. This both increases application payload as well as makes reverse engineering a lot easier. You usually don't want either. A minidump should really be your first option. – IInspectable Apr 11 '16 at 16:42
  • @IInspectable, man! Dumps do take time to deliver because of large size. Also, dumps would have whole memory of process, which is private to the organization, not many would allow such thing. A few lines of log, having only the functions that caused the issue is super-fast. You probably didn't face it. – Ajay Apr 11 '16 at 16:45
  • @Ajay: Uhm... you don't have to go looking for anything. First, a minidump can be as compact and tiny as you want. You can package helpful information and still keep it down to a few tens of kilobytes. You don't have to look for PDB's either, if you set up a symbol server. Of course, this goes along a source server, so you don't have to go looking for source code either. With that infrastructure, you simply load up the minidump in a debugger, and have the source code, with the correct version, right there. I guess you never went there... – IInspectable Apr 11 '16 at 16:47
  • No worries. Do that way. But SEH and C++ are different. – Ajay Apr 11 '16 at 16:48
  • @Ajay: Minidumps do not necessarily contain the entire address space of a process. You have extremely fine grained control over which information goes in, and which information doesn't go into a dump. Why do you keep talking about things you have not the least bit of a clue about? – IInspectable Apr 11 '16 at 16:53
  • @IInspectable Man, I stopped the discussion. I am very much aware about different parameters. Wrote a global level exception handler for a server grade application, and for a Windows service. Your approach is different, mine is different. I am not finding your bad (let my bad approach stay with me :) ). Mini-dump with low information doesn't help. And please don't insult! – Ajay Apr 11 '16 at 16:57
  • 2
    @Ajay: At any rate, I just implemented a test application, Visual Studio 2015, 64 bit, running on Windows 10. Consisting of the single line of code: `throw 42;`. Single-stepped into the assembly and wound up at [RaiseException](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680552.aspx). I don't know why you insist, that C++ exceptions wouldn't be implemented on top of SEH exceptions. Visual Studio always did it this way. – IInspectable Apr 11 '16 at 17:26
  • @IInspectable There is a [thread on SO](http://stackoverflow.com/questions/3786647/difference-between-a-c-exception-and-structured-exception) where Hans Passant explains that C++ **are** in fact implemented as SEH exceptions, just as was my understanding from reading MSDN. So perhaps it is enough to identify the offset of the CONTEXT* field from address of the exception object. +1 for disassemby. – Lothar Apr 11 '16 at 17:34
  • @Ajay You are right, throwing exceptions with useful information is more important than trying to cast an oracle looking a stack dump. – Lothar Apr 11 '16 at 17:46
  • @IInspectable, you are right about `RaiseException`. Both kind of exceptions are thrown by it. But can you handle `throw 10;` with SEH? Can you handle `RaiseException(0xDEAD, 0, 0, 0);` with `try`/`catch`? You cannot. I did dive into this API, but now I don't have any concrete info on how it works (differentiates) with C++ exception than SEH. – Ajay Apr 11 '16 at 18:03
  • `Exception thrown at 0x772CC52F in abc.exe: Microsoft C++ exception: int at memory location 0x0047FC6C.` - May be vc-runtime is internally using SEH and wrapping it into C++ `catch(object)` based exception. For exceptions, hardware interrupt is required (user API is `RaiseException`) – Ajay Apr 11 '16 at 18:07
  • @Ajay: There are no two kinds of exceptions. There are only SEH exceptions, and C++ exceptions are SEH exceptions with a specific exception code (0xE04D5343). Both the runtime as well as the compiler know how about this specific exception code. – IInspectable Apr 11 '16 at 18:14
  • @IInspectable, all exceptions are nothing but interrupts. But there is logical separation. No all interrupts are exceptions. Not all exceptions are C++ or SEH. You can keep proving your point, but for compiler they are different. Even with `/EHa` there are SEH exceptions that cannot be caught with `try`/`catch`. Keep debating. I won't. – Ajay Apr 11 '16 at 19:42
  • .@IInspectable is correct. In the Visual C++ implementation, a C++ exception is just a structured exception (SEH exception) with a specific exception code. An `__except` statement can handle a C++ exception and a `__finally` statement will run when the stack is unwound due to a C++ exception (this will happen whether the C++ exception was "caught" by a `catch` statement or an `__except` statement). – James McNellis Apr 11 '16 at 21:00
  • @Ajay: Of course you cannot catch SEH exceptions using `try`/`catch`, because `catch` is designed that way (at least since VS 2002). However, you can intercept **all** C++ exceptions using `__except`. That's simply because C++ exceptions **are** SEH exceptions. I'm not trying to prove *my point*. I was responding to your comment that was fairly off target. – IInspectable Apr 11 '16 at 21:01
  • 1
    @Ajay: The person responsible for the CRT that ships with Visual Studio appears to [agree with me](http://stackoverflow.com/q/36551933/1889329#comment60718774_36551933). Why don't you go tell him, that he's wrong? And with that out of the way, with all undue respect, give it a rest. You were wrong. Get used to it, it happens a lot. – IInspectable Apr 12 '16 at 07:56

1 Answers1

1

No, an optimizing C++ compiler has no need to keep the CONTEXT, effectively a copy of the stack, around. So when we are inside the catch it can already be gone. You can easily get the stack trace however by attaching to Debug events and Accessing Thread Context Information from Threads of a Process Being Debugged when exceptions are thrown.

Perhaps it could somehow be done as the context is saved in the beginning of the Unwind Procedure and we could try to analyze the stack similar to a Crash Course on the Depths of Win32™ Structured Exception Handling, effectively using the PBP and an offset, possibly requiring to enable SEH. However inner details of exceptions handling have been changed between different versions, platforms and compiler settings, so this is a rather fragile approach and use of SEH is discouraged for C++:

Structured Exception Handling (C/C++) (Visual Studio 2015)

Windows and Visual C++ support structured exception handling (SEH), we recommend that you use ISO-standard C++ exception handling because it makes code more portable and flexible. Nevertheless, in existing code or for particular kinds of programs, you still might have to use SEH.

Lothar
  • 860
  • 6
  • 21