How to catch SEH thrown from ntdll.dll's TppRaiseInvalidParameter? - c++

I am using MSVC2019 and COM and compiling using /EHa
getting a SEH from ntdll.dll from TppRaiseInvalidParameter that I am trying to catch but seem unable to. I know exactly why the exception is thrown, but that is not the issue here.
I tried using all the mechanisms described in the MSDN docs (__try/__except, _set_se_translator, SetUnhandledExceptionFilter), but none seem to trigger in this case.
I also tried raising exceptions using RaiseException and RtlRaiseException (used by TppRaiseInvalidParameter) and those seem to be caught no problem in the __except handler.
The only thing I've been able to spot in TppRaiseInvalidParameter is that it calls __SEH_prolog4_GS at the beginning, but from what I've read that is normal code generated by the compiler for SEHs, but I'm new to SEHs in general.
My questions are: why can't I catch that exception? Is there any way to catch it?
Minimal code for reproduction
extern "C"
{
void (WINAPI* TppRaiseInvalidParameter)();
}
void func()
{
__try
{
HMODULE ntdll;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "ntdll.dll", &ntdll);
TppRaiseInvalidParameter = reinterpret_cast<decltype(TppRaiseInvalidParameter)>((LONG)ntdll + 0x104EBDL); // it's not an exported function and your offset may be different
TppRaiseInvalidParameter();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
puts("exception caught");
}
}

Related

Why does iostream require the exception handler to be called while using vcvarsall.bat to compile 'Hello World'?

Attempting to compile the following code with vcvarsall.bat in command line throws a warning saying that the exception handler is needed in the code but not called before using /EHsc.
Code:
#include <iostream>
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}
The batch file:
#echo off
cl C:\Development\..\basicmath.cpp
The warning:
C:\...\ostream(746): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:...\basicmath.cpp(10): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)' being compiled
Line 743 - 754 of ostream line 746 (from error) is _TRY:
if (!_Ok) {
_State |= ios_base::badbit;
} else { // state okay, insert
_TRY_IO_BEGIN
if ((_Ostr.flags() & ios_base::adjustfield) != ios_base::left) {
for (; 0 < _Pad; --_Pad) { // pad on left
if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) {
_State |= ios_base::badbit; // insertion failed, quit
break;
}
}
}
Adding /EHsc to my batch file will allow it to run but I would like to know why this is. Why does this block of code from the file for output require EHsc to be called?
MSDOCS says EHsc is for cleanup to prevent memory leaks, what is causing the leak and why do they need an external program to fix the leak instead of fixing it in the same file (this may sound rude but its just ignorant)?
Edit: thank you for pointing out its a warning and not an error.
Short answer:
Add /EHs or /EHsc to your compilation options as the documentation suggests. It's the most portable option regarding exceptions handling, if you will ever need to execute the same code on Unix machine.
Long answer:
There are two parts to this question. First is why the warning occurs in iostream and the second is what does the warning mean.
Why are there exceptions in iostream?
The default behaviour of streams in C++ is exceptionless - any failure is represented by setting an internal fail bit, accessible with eof(), fail() and bad() functions. However, you can change this behaviour to throwing exceptions on failure by using exceptions() method on stream. You can choose which fail bits trigger exceptions, but the main point is that the code must be there by standard. The warning seems to analyze only that - it notices a possible path where throw occurs and reports a warning.
What does the warning mean?
From the Microsoft documentation (emphasis mine):
By default (that is, if no /EHsc, /EHs, or /EHa option is specified), the compiler supports SEH handlers in the native C++ catch(...) clause. However, it also generates code that only partially supports C++ exceptions . The default exception unwinding code doesn't destroy automatic C++ objects outside of try blocks that go out of scope because of an exception.
The issue is that (for some reason) MSVC compiler by default generates assembly which is wrong according to the standard. Stack unwinding will not be perfomerd when exception is thrown, which may cause memory leaks and other unexpected behaviours.
An example correct C++ code, which has a memory leak under the default setting:
void foo()
{
std::string str = "This is a very long string. It definitely doesn't use Small String Optimization and it must be allocated on the heap."
std::cout << str;
throw std::runtime_error{"Oh no, something went wrong"};
}
int main()
{
try
{
foo();
}
catch (std::exception&)
{
// str in foo() was possibly not released, because it wasn't deleted when exception was thrown!
}
}
So the final answer would be:
If you plan to use Structured Exceptions (like divide-by-zero or invalid memory access errors) or use a library that uses them, use /EHa
If you don't need to catch SEs, choose /EHs for compatibility with C++ standard and portability
Never leave the defaults, always set /EH to one alternative or another, otherwise you will have to deal with strange behaviours when using exceptions.
That's a warning so your current program compiles fine. But problems come up in programs as such:
#include <exception>
#include <iostream>
struct A{
A(int x):x(x) {
std::cout<<"Contructed A::"<<x<<'\n';
}
~A() {
std::cout<<"Destructed A::"<<x<<'\n';
}
private:
int x;
};
void foo() {
A a{2};
throw std::bad_exception{};
}
int main()
{
A a {1};
try {
foo();
} catch(const std::bad_exception& ex) {
std::cout<<ex.what()<<'\n';
}
return 0;
}
Using cl test.cpp yields the output:
Contructed A::1
Contructed A::2
bad exception
Destructed A::1
While using cl test.cpp /EHsc yields:
Contructed A::1
Contructed A::2
Destructed A::2
bad exception
Destructed A::1
This behavior is explained by the documentation for the warning C4530:
When the /EHsc option isn't enabled, automatic storage objects in the
stack frames between the throwing function and the function where the
exception is caught don't get destroyed. Only the automatic storage
objects created in a try or catch block get destroyed, which can lead
to significant resource leaks and other unexpected behavior.
That explains a {2} not being destructed when the program wasn't compiled with /EHsc.
And of course,
If no exceptions can possibly be thrown in your executable, you may
safely ignore this warning.
So, for a program like
#include <cstdio>
int main()
{
std::printf("hello world\n");
return 0;
}
cl.exe quietly compiles.

Catch a specific exception by its name cpp

I use pcl 1.7 tracking code and In some cases this method:
tracker_->compute ();
Gives me these errors:
[pcl::ApproxNearestPairPointCloudCoherence::initCompute] PointCloudCoherence::Init failed.
[pcl::ApproxNearestPairPointCloudCoherence::compute] Init failed.
I now know that error is thrown and I would like to catch exactly this error to tell the program what to do if this error occurs. I tried like this:
try
{
tracker_->compute ();
}
catch (...)
{
std::cout<<"inside the exception"<<std::endl;
}
To catch all the errors but it did not work..... And also with
catch(pcl::ApproxNearestPairPointCloudCoherenceException &e)
my program did not even compile....
So any ideas what I do wrong?
I browsed the source in order to look for the location where the error is raised, and found out that in your specific case it is raised by
if (!PointCloudCoherence<PointInT>::initCompute ())
{
PCL_ERROR ("[pcl::%s::initCompute] PointCloudCoherence::Init failed.\n", getClassName().c_str());
return (false);
}
so you see, there is no throw xxx here but only a macro which hides the actual error handling from us.
To find out what exactly was happening, I then searched for a definition of PCL_ERROR and the search yielded that it is defined in the file print.h as
#define PCL_ERROR(...) pcl::console::print (pcl::console::L_ERROR, __VA_ARGS__)
with pcl::console::print being a function simply printing the error, not throwing an exception.
So, you cannot catch the error because it is not an exception, but rather only plain text written to the console.

Cannot catch exception from shared library in main.cpp

I'm currently working on a game with a plugin based architecture. The executable consists mostly of a shared library loader and a couple of interface definitions. All the interesting stuff is happening in dynamic shared libraries which are loaded at start up.
One of the library classes throws an exception under certain circumstances. I would expect to be able to catch this exception and do useful stuff with it but this is where it gets weird. See following simplified example code:
main.cpp
int main()
{
try
{
Application app;
app.loadPlugin();
app.doStuffWithPlugin();
return 0;
}
catch(const std::exception& ex)
{
// Log exception
return 1;
}
}
Application.cpp
...
void doStuffWithPlugin()
{
plugin.doStuff();
}
...
Plugin.cpp
...
void doStuff()
{
throw exception_derived_from_runtime_error("Something is wrong");
}
...
Plugin.cpp exists in a dynamic shared library which is successfully loaded and which has afterwards created an object of class Plugin. The exception_derived_from_runtime_error is defined in the application. There is no throw() or noexcept.
I would expect to catch the exception_derived_from_runtime_error in main but that doesn't happen. Compiled with GCC 4.8 using C++11 the application crashes with This application has requested the Runtime to terminate it in an unusual way..
I replaced catch(const std::exception& ex) with catch(...) but that didn't make any difference. The weird part is if i catch the exception in doStuffWithPlugin() it works. If i rethrow it using throw; it fails again but it can be caught if i use throw ex;:
Application.cpp
void doStuffWithPlugin()
{
try
{
plugin.doStuff();
}
catch(const exception_derived_from_runtime_error& ex)
{
// throw; <- Not caught in main().
// throw ex; <- Caught in main().
}
}
Hopefully somebody has an idea. Thanks for every help you can give.
As mentioned in the comments this seems to be a problem with shared libraries on Windows. The behavior occurs if the library is unloaded and an object created in this libraries remains in memory. The application seems to crash immediately. The only reference to this problems are found if gcc as an cross compiler or MinGW is used. See also https://www.sourceware.org/ml/crossgcc/2005-01/msg00022.html

Why the c++ object destructor not called when luaL_error is called?

I have a piece of code like this
class Test
{
public:
Test() {printf(">>> Test()\n");}
~Test() {printf(">>> ~Test()\n");}
}
int myFunc(lua_State *L)
{
Test t;
luaL_error(L, "error");
return 0;
}
I know when lua complied by c complier it use longjmp to raise an error. So, I compiled it use c++ compiler so that it use c++ exception to hand the errors and the destructor should be called even if an error is thrown. But my problem is that the object's destructor is not called.
However, the following code is working (the destructor is called)
int myFunc(lua_State *L)
{
Test t;
throw(1) // just for testing
return 0;
}
Why this happend? I'm sure the LUAI_THROW macro is interpreted as throw key word.
The function luaL_error() will call exit() which cancels the whole execution of your program! The desctructor is not called then because the scope where Test t is in does not end. You should use a different functionality to be able to recover from an error. How do you call the error from lua? I think you need to do a protected call using lua_cpcall to go arround this exit on error feature!
The root cause is related to exception handling mode in visual c++ compiler. I use the lua function (such as luaL_error) with extern "C" modifier to prevent compiler from name-mangling. And the default exception handling mode is /EHsc which assume extern "C" function don't throw exception. So, the exception can't be catched. The solution is change /EHsc to /EHs.
For more information please refer to http://msdn.microsoft.com/en-us/library/1deeycx5.aspx.

How can MSVC6 handle exceptions from extern "C" functions?

I'm working on an application written in Visual Studio 6 (I know, FML) that is calling functions in a DLL using LoadLibrary and GetProcAddress. The newer code can't compile in VC6, and needs a newer compiler. The DLL has a few functions that construct a C++ object, and then the VC6 program uses the object through an abstract class.
This works just fine usually, but it runs into problems when the functions retrieved by GetProcAddress throw exceptions -- even when the exceptions are caught within the DLL. I've noticed that this doesn't happen when the abstract class's methods throw an exception. Things work normally in that case.
What am I doing wrong here? How can I make VC6 generate code to handle the exceptions properly?
Edit: Here's an example of a function that causes the program to crash:
extern "C" __declspec(dllexport) Box* getBox(const char* addr)
{
try {
return createBox(addr);
} catch (std::exception& ex) {
LOG_ERROR("Open failed: " << ex.what());
return 0;
} catch (...) {
LOG_ERROR("Error while opening.");
return 0;
}
}
You cannot do inheritance cross compiler versions like that. It almost works but exceptions and a few other things go crazy.