I'm curious how Windows handles exceptions. More exactly, how Windows find the catch block of a try / catch. I saw that the compiler makes a separate function in assembly for catch block. Since the catch block was represented by another function in assembly, I couldn't find any correlation between the instruction that was generating the exception and the RUNTIME_FUNCTION entries from .pdata section.
I tried to put a breakpoint on RaiseException, RtlRaiseException and RtlVirtualUnwind but all I could find was the address after the RaiseException call. Tried to debug a divide by 0 exception, but it looks like the debugger has some additional exception handlers and the message in the catch block was not printed.
Any additional information about Stack Unwinding on Windows 64bit are welcome :D.
The exceptions are handled by exception handler routines.
When you add a try/catch block to your C++ code you will see that the compiler added __CxxFrameHandler3 to your import table (providing that the MSVCRT is not statically linked). So this is your exception handler that will be called when an exception occurs in the try block.
Another one __C_specific_handler is imported when you add __try/__except block to your C or C++ code.
There are a few others but these two are used in the C/C++ code.
To answer your question, the best way is to hook (replace the import table pointer with a pointer to your local routine) one of these functions and see how your "handler" will be called when an exception is thrown.
With the goal of finding C++ catch you can set Vectored Exception Handler and set a breakpoint in it. VEH goes before frame-based handlers, so it it not too late:
LONG NTAPI vh(EXCEPTION_POINTERS* ExceptionInfo)
{
return EXCEPTION_CONTINUE_SEARCH;
}
AddVectoredExceptionHandler(TRUE, vh);
Alternatively, if you want to set breakpoint closer to catch block, have __try...__except deeper in call stack than target catch block, in __except expression return EXCEPTION_CONTINUE_SEARCH and have your breakpoint there.
Related
The Windows API CopyFile function is rather straightforward:
BOOL CopyFileW(
[in] LPCWSTR lpExistingFileName,
[in] LPCWSTR lpNewFileName,
[in] BOOL bFailIfExists
);
...
If the function fails, the return value is zero. To get extended error
information, call GetLastError.
However, I found this gem in our C++ source code, dating back to Oct / 2006:
try { //Exception, if the file already exists and is write protected
bCopyOK = CopyFile(csSourceFile, csDestinationFile, bFailIfExists);
} catch (...) {
bCopyOK = FALSE;
}
I even found the old ticket title (of course without details): "function 'CopyFile' throws Exception if Destination is write protected, catch Exception" :-)
Even today we still compile with /EHa, so this would have caught any SEH exceptions raised.
Now, at this point in time we would've been using Visual Studio 6 on Windows XP, and that one had all kinds of quirks, but still: I have a hard time imagining this function ever raising an exception (apart from invalid/null parameters and such).
Does or DID Win32 CopyFile(W) ever raise a (SEH) exception?
NO.
at first not exist SEH exceptions at all. SEH this is type of exception handler but not type of exception. another type of handlers (not exceptions) is VEH.
exception can be raised or via invoke RaiseException /RtlRaiseException / ZwRaiseException or by CPU. of course CPU exception alwas can be raised (in case lpExistingFileName or lpNewFileName for instanse point to invalid memory ) but CopyFileW never call RaiseException - by fact and by documentation.
//Exception, if the file already exists and is write protected
so in what problem ? create write protected file lpNewFileName and call CopyFile and test result. will be exception or error code returned
// Self answer, with historical perspective.
It is not documented to throw exceptions, as is apparent from the current docs linked above.
Both the other answer and also, e.g. Do DeleteFile() Or CopyFile() throw exceptions? quite definitely assert that there should be no exception being raised.
However, as is mentioned in comments:
Very few API calls are documented to raise SEH exceptions, but that
doesn't mean that they won't, or prevent SEH exceptions raised in
foreign code from passing through.
and in the linked question:
comment: ... Some odds that getting rid of the installed anti-malware product can rescue it, ymmv. ...
A: It was ... corporate info safety system, anti-malware like product.
It is very well possible that the original developer could actually reproduce this behavior on his machine, and swallowing the error "fixed" it well enough back then.
Things have improved since then. Given that no reproduction is possible in current code, and given that this only works with /EHa anyways, the try-catch is a candidate for cleanup.
Given the basic code:
std::vector<int> foo(10);
foo.at[100] = 42;
This will throw an std::out_of_range as expected, and the default behaviour on my machine is to print a string like:
terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 100) >= this->size() (which is 10)
If I wrap the code with a try/catch:
try {
foo.at[100] = 42;
} catch (std::out_of_range e) {
printf("Error at %s line %d\n", __FILE__, __LINE);
}
I can of course get the line where the problem occurs, but if the code has tens of uses of at and I do this:
try {
functionThatCallsAtFromLotsOfPlaces();
} catch (std::out_of_range e) {
printf("Error at %s line %d\n", __FILE__, __LINE);
}
I only get the line number of the catch, not the throw.
On the other hand, if I load up the program in gdb and type catch throw, gdb will hand control back to me at the throw, so I can easily trace where exactly the error is, not where it was caught. Is there a mechanism in C++11, or gcc-specific, where I can emulate what gdb is doing?
Note, there is this question, but that is for signal errors; it doesn't work for me for normal throws.
boost::exception e.g. stores the stack trace on an initial throw. std:: exception doesn't and hence you can't see the stack trace before it was unrolled. Rethrowing the original exception nested in something like a Boost exception would provide you a stacktrace, but still only up to the creation of the nested exception.
There is no way around that, all you could do, is installing a custom handler to catch exceptions as they are thrown, but that is very much compiler and runtime specific. Essentially you would use the ports which area designed for debugging.
Anyway, you should really not care about stack traces for an exception you have caught. It's better to just let the exception crash in such case, and utilize full crash dump creation with Breakpad or alike, for posthum analysis with not only full stack trace, but also stack contents intact. Only catch exceptions from which you intend to recover, everything else is just error concealing (even if not intended) and makes debugging harder.
The 64-bit Windows ABI defines a generalized exception handling mechanism, which I believe is shared across C++ exceptions and structured exceptions available even in other languages such as C.
If I'm writing an x86-64 assembly routine to be compiled in nasm and linked into a C or C++ library, what accommodations do I need make on Windows in terms of generating unwind info and so on?
I'm not planning on generating any exceptions directly in the assembly code, although I suppose it is possible that the code may get an access violation if a user-supplied buffer is invalid, etc.
I'd like the write the minimum possible to get this to work, especially since it seems that nasm has poor support for generating unwind info and using MASM is not an option for this cross-platform project. I do need to use (hence save and restore) non-volatile registers.
As a general rule, Windows x64 requires all functions to provide unwind information. The only exception is for leaf functions which do not modify rsp and do not modify any nonvolatile registers.
Judging by the context of your question, what you really want to know is the practical consequences of not providing unwind information for your non-leaf assembly functions on x64 Windows. Since C++ exceptions are implemented based on SEH exceptions, when I talk about exceptions below, I mean both all "native" (access violation, something thrown using RaiseException, etc.) and C++ exceptions. Here's a list off the top of my head:
Exceptions won't be able to pass through your function
It's important to note that this point is not about throwing an exception, or an access violation happening directly in your function. Let's say your assembly code calls into a C++ function, which throws an exception. Even if the caller of your assembly function has a matching catch block, it will never be able to catch the exception, as unwinding will stop at your function without the unwind data.
When walking the stack, the stack walk will stop at the function without unwind data (or go astray; the point is, you will get an invalid call stack)
Basicaly, anything that walks the stack is screwed if your function is present on the call stack (debuggers when displaying the call stack, profilers, etc.)
Registered Unhandled Exception Filters will not be called back if an exception gets thrown, and your assembly function is on the call stack
This interferes with anything that relies on UEFs. Custom crash handlers, for instance. Or something potentially more relevant: std::terminate won't be called back in this case, if your program throws a C++ exception, that is unhandled (as it's dictated by the C++ standard). The MSVC runtime uses a UEF to implement this, so this won't work as well.
Are you developing a 3rd party library? If that's the case, the importance of the above points will depend on the use case of your clients.
I have a Windows Store application (for Windows 8) written in C++/CX and I have wrapped a chunk of my code in a try/catch block.
The catch block is working and catches an exception, but so far I only seem to be able to print out the "message" part of the exception and not the full exception stack:
try
{
...
}
catch(Exception^ e)
{
LogMessage("Exception caught: " + e->ToString());
}
When the exception is caught, the LogMessage outputs only the following text:
"Exception caught: The object already exists"
I've tried e->ToString() and e->Message, but both result in the same output and that does not include the full exception stack.
In C# it seems to be really easy to output the full exception stack, so I am not sure why it seems to be difficult in C++/CX ?
This is difficult in C++/CX because determining what functions would be in the stack requires code to parse debugging symbols. In C#, the CLR does work at runtime to remember which methods are in the stack, but in C++/CX, the names of functions are not recorded in the resulting binary. Put another way, the stack trace you get in C# depends on a C# feature: reflection.
Moreover, an exception may result from a call into code which is a plain COM API, rather than a C++/CX API. In such cases, the exception is generated from an error HRESULT return code underneath, not at the time where the exception is thrown. (Indeed, this is what happens whenever crossing component boundaries; this is handled with plain COM even if both sides of the operation are C++/CX) As such, the stack you would need for a trace is no longer available.
C++ exceptions do not record a stack trace. On the plus side, from native programs you can collect a minidump when an unhandled exception occurs, which lets you view the stack using a debugger if you need to.
Keep in mind that a C++/CX program is pure unmanaged C++ code. The CX language extension only makes it easy to consume WinRT types in your C++ code, it hides the COM implementation details. So it gets the full treatment of the code optimizer. Which does not try to ensure that stack walks can be safely performed. Particularly so in leaf functions that don't throw exceptions. It will readily omit setting the EBP register, the important one that indicates the base of a stack activation frame.
This is not the case in managed code, like C#. Stack walks are very important in a garbage collected runtime environment. The garbage collector must perform them to find object references when it collects garbage. Code Access Security also depends on stack walks. A happy side effect is that it now also becomes very easy to generate a stack trace for an exception. It is even exposed in the framework api, the StackTrace class lets you walk the stack in your own code.
No simple fix for this, you need debugging symbols to have a shot at it. And StackWalk64 from the DbgHelp api. With odds that you still don't get anywhere because the program crashed somewhere in the bowels of a Windows function. Speed trumps convenience in C++.
An MFC, C++ application I'm working on seems to be throwing an exception deep inside a device driver. (It's an access violation writing to a NULL pointer from the looks of things. The details of the crash are not what is interesting me right now, however...)
I can get the Visual Studio Debugger to break when the exception occurs through the Exceptions dialog. What I would like to know though is where the exception is being caught. Visual Studio can pass the exception on to the program being debugged, but there doesn't seem to be anyway (that I know of) to single step to the next instruction so I can view the callstack from the exception handler's point of view.
Does anyone know whether it is possible to step to the exception handler that will catch the exception or not?
Cheers,
James
With WinDbg, you can use the !exchain command. With !exchain -c, it will show your C++ destructors and catch blocks. e.g.
Try block 0
Catch block 0, type: module!my_exception `RTTI Type Descriptor'+0 (6071409c)
handler: module!catch_block+582 (6063bcc2)
Then you can set a breakpoint with bp 6063bcc2.
I don't know of a way to do this in Visual Studio.
At the point when the exception is being thrown you should have a call stack available to you in the debugger -- by looking at each stack frame from the point of the throw to main, you should be able to find the first frame with a try/catch block wrapping the call to the next routine in the frame. As long as that try/catch block handles the type of exception being thrown, that's where it'll land.