Exceptions on Linux from a shared object (.so) - c++

I have a test program called ftest. It loads .so files that contain tests and runs the tests that it finds in there. One of these tests loads and runs a .so that contains a Postgres database driver for our O/RM.
When the Postgres driver throws an exception which is defined in that .so file (or one that it links to, but ftest does not link to) and is caught by the test framework the exception destructor triggers a segfault.
This segfault happens whenever the compiled exception is in a .so that has been dynamically loaded (using dload).
This sort of thing works fine in Windows which has the same architecture. We don't really want to restrict ourselves to only use exceptions that are from the core libraries -- add-ins should be free to create their own exception classes and have them handled normally.
The exceptions are sub-classes of std::exception. Sometimes the exceptions may be defined in libraries (such as libpqxx) which means that exceptions are sometimes out of our control too.
Exceptions are thrown using something like:
throw exception_class( exception_arguments );
And are caught using:
catch ( std::exception &e ) {
// handler code
}
Is there some special compiler option needed to get this working? Do we need to switch to throw exceptions via throw new exception_class( args ) (we don't really want to do this)?

Assuming your using gcc -
Append -Wl,-E when you build the executable calling dlload(). This exports all type info symbols from the executable, which should allow the RTTI (when catching the exception) to work properly.
VC++ uses string compares to match typeinfo, results in slower dynamic_cast<> etc but smaller binaries. g++ uses pointer compares.
I encountered the same problem when attempting to use pure virtual interfaces classes implemented in a run-time loaded .so.
There are a few articles relating to the subject floating around on the net as well.
hope that helps,
Hayman.

Related

Exception Handling in /clr MFC Application (compiled with /EHa)

We have a large MFC application that is in the process of being updated. It has been modified to add in some .NET components (some of the DLLs now have managed & native classes), the idea is that the old code will be phased out eventually.
The app has many DLLs with native C++ classes exported, and used by the application.
On trying to test the app we now find ANY exception seems to cause the app to crash, even though these exceptions are in theory being caught in the same function.
example:
CString AddressClass::GetPostalAddress()
{
CString address;
try {
address = (LPCSTR)(_bstr_t)m_pCommand->GetParameters()->Item["PostalAddress"]->Value;
}
catch ( _com_error& )//exception occurs if postal address is NULL
{
address = _T("");
}
return address;
}
The _com_error is not being caught when compiling with /clr and /EHa (Vs2015 update 3). Without /clr it works fine and has been operational for years. From the documentation I have read my understanding is this should work, but clearly I am mistaken.
The code responsible for generating the error is in comutil.h:
inline void CheckError(HRESULT hr)
{
if (FAILED(hr)) {
_com_issue_error(hr);
}
}
The information from the debugger is:
An exception of type 'System.Runtime.InteropServices.SEHException' occurred in XXX.dll and wasn't handled before a managed/native boundary
Additional information: External component has thrown an exception.
Is there anyway to get this working without rewriting huge amounts of code?
Thanks.
Answer from short comment, since it seems to have helped:
Generally speaking: You should not compile these with /clr. Separate your old code vs your new CLR-using code, just compile new code with /clr, compile old code/files directly native. You can still link everything together in a clr-enabled DLL.
What we do is to compile all the native stuff in separate static LIB projects, and then link these into /clr enabled projects - having separate compiler switches for individual source files inside one project is always a tad confusing. But then, it may still be the way to go for you. Depends on the mixture and calling patterns, I guess.
I'll add that I view /clr mostly as a rather powerful glue system, than something you should target for the full app stack.

MSVCR and CRT Initialization

Out of curiosity, what exactly happens when an application compiled with the MSVCR is loaded, resp. how does the loader of Windows actually initialize the CRT? For what I have gathered so far, when the program as well as all the imported libraries are loaded into memory and all relocations are done, the CRT startup code (_CRT_INIT()?) initializes all global initializers in the .CRT$XC* sections and calls the user defined main() function. I hope this is correct so far.
But let's assume, for the sake of explanation, a program that is not using the MSVCR (e.g. an application built with Cygwin GCC or other compilers) tries to load a library at runtime, requiring the CRT, using a custom loader/runtime linker, so no LoadLibrary() involved. How would the loader/linker has to handle CRT initialization? Would it have to manually initialize all "objects" in said sections, does it have to do something else to make the internal wiring of the library work properly, or would it have to just call _CRT_INIT() (which unpractically is defined in the runtime itself and not exported anywhere as far as I am aware). Would this mix-up even work in any way, assuming that the non-CRT application and the CRT-library would not pass any objects, exceptions and things the like between them?
I would be very interested in finding out, because I can't quite make out what the CRT has an effect on the actual loading process...
Any information is very appreciated, thanks!
The entrypoint for an executable image is selected with the /ENTRY linker option. The defaults it uses are documented well in the MSDN Library article. They are the CRT entrypoint.
If you want to replace the CRT then either pick the same name or use the /ENTRY option explicitly when you link. You'll also need /NODEFAULTLIB to prevent it from linking the regular .lib
Each library compiled against the C++ runtime is calling _DllMainCRTStartup when it's loaded. _DllMainCRTStartup calls _CRT_INIT, which initializes the C/C++ run-time library and invokes C++ constructors on static, non-local variables.
The PE format contains an optional header that has a slot called 'addressofentrypoint', this slot calls a function that will call _DllMainCRTStartup which fires the initialization chain.
after _DllMainCRTStartup finishes the initialization phase it will call your own implemented DllMain() function.
When you learn about programming, someone will tell you that "the first thing that happens is that the code runs in main. But that's a bit like when you learn about atoms in School, they are fairly well organized and operate acorrding to strict rules. If you later go to a Nuclear/Particle Physics class at university, those simple/strict rules are much more detailed and don't always apply, etc.
When you link a C or C++ program the CRT contains some code something like this:
start()
{
CRT_init();
...
Global_Object_Constructors();
...
exit(main());
}
So the initialization is done by the C runtime library itself, BEFORE it calls your main.
A DLL has a DllMain that is executed by LoadLibrary() - this is responsible for initializing/creating global objects in the DLL, and if you don't use LoadLibrary() [e.g. loading the DLL into memory yourself] then you would have to ensure that objects are created and initialized.

Encountering errors when using C++ interop on old MFC/Win32 application

I have inherited an old MFC/Win32 C++ application who's source code I am not supposed to edit.
This MFC application needs to host an old MFC/Win32 C++ DLL. This DLL also tries to make function calls through a Mixed-mode wrapper to a managed C++/CLI DLL. I know it sounds a little confusing, so here's a diagram of what I mean:
Old MFC/Win32 Application (NO CLR)
---> Hosting old MFC/Win32 DLL (NO CLR)
---> Making function calls to Mixed-Mode wrapper (CLR)
---> Sending function calls to C++/CLI DLL (CLR)
My problem currently is that when I try to mount an object of the C++/CLR wrapper class let's say WrapperClass WC;, the MFC/Win32 application encounters an "Unhandled exception."
I have a feeling that I may need to somehow host the CLR in a separate process in order to be able to make the object. Is this the right idea? Or am I completely out of whack here?
The code compiles time and this only occurs at run-time.
Any ideas?
Here is an example of the code I am trying to run:
MFC/Win32 DLL
#include "WrapperClass.h"
BOOL Test::bTest() //This function is called elsewhere within MFC/Win32 DLL
{
DWORD dwTest;
WrapperClass WC; //Unhandled exception here!
return WC.FunctionToCall(dwTest); //FunctionToCall is a BOOL
}
Mixed-Mode Wrapper Class
BOOL WrapperClass::FunctionToCall(DWORD dw)
{
GCHandle h = GCHandle::FromIntPtr(IntPtr(m_impl)); //m_impl def'd as void *
CPPCLIClass^ CCC = safe_cast<CPPCLIClass^>(h.Target);
return (BOOL)CCC->FunctionToCall(dw);
}
C++/CLI DLL
bool CPPCLIClass::FunctionToCall(UInt32 ui32)
{
if (ui32 == 42)
{
return true;
}
}
UPDATE:
I've managed to coax a real exception out of the program. I am now receiving a System.IO.FileNotFound exception with additional information stating:
An unhandled exception of type 'System.IO.FileNotFoundException' occured in
Unknown Module.
Additional information: Could not load file or assembly 'CPPCLIProject,
Version=1.0.4351.29839, Culture=neutral, PublicKeyToken=null' or one of its
dependencies. The system cannot find the file specified.
Does this mean anything? I understand that it apparently cannot find CPPCLIProject (Note: this is not the wrapper project), but then if I'm linking on the .lib file from the Mixed-mode wrapper, how would I not receive linker errors then?
Are you sure that the implementation of WrapperClass::FunctionToCall() isn't throwing the exception? It looks like you're caching the memory location of a CLR object, and then trying to call one of its members. I think the CLR is free to move objects around, so it's possible that you're trying to use an object that has moved.
If you change the implementation of WrapperClass::FunctionToCall() to something simple (i.e. create a CLR object, call a member function), do you still get the same unhandled exception?
UPDATE: Which class is in CPPCLIProject - CPPCLIClass? Assuming this project represents the C++/CLI DLL, it sounds like it just can't find the assembly to load it when it needs to call your class.
Where is this assembly on disk relative to the rest of the application? If your root EXE is unmanaged (which it sounds like it is, since it is MFC/Win32), then the CLR looks in the EXE's directory and the GAC in order to load assemblies (I don't think it looks in the Path, but I'm not positive on that).
So if the CPPCLIProject isn't in the same directory as the EXE, that could be your problem.
Your best bet is to
run under a debugger (add the additional DLLs with debug information to the debug session)
enable break on all (first-chance) exceptions
trace/assert all HRESULT codes
in general try to catch
C++ exceptions (try/catch...)
Windows Structured Exceptions (IIRC _try/_catch, but see MSDN)
The idea is to convert the 'unkown exception' into 'known exception'.
Normally speaking there is no need to host the CLR part out of process. This is what a mixed-mode DLL is about. Then again, if this is legacy code, you might be running into complicated mixes of runtime dependencies that, shall we say, could clash.
Further thoughts:
If I understand correctly, you have the option to recompile all sources (just not touch the legacy codebase?). If so, make sure all code is compiled against the same version (think Service Packs) and type (think Static vs Dynamic/Multithread/Debug) of the runtime libraries.
While you are checking additional pathways, keep an eye on potentially conflicting dependencies on
ATL server libs
MFC libs (again static vs dynamic/Multithread/Debug flavours).

Uncaught exception in a callback from a 3rd party static library

I am compiling my program with a 3rd party library. That library contains an error callback if an error occurs internally. Inside that error callback I am throwing an exception and I have a unit test to verify that when I do something invalid that the exception is thrown. This all works beautifully in Windows, but when I test this in linux (fedora) I am getting an abort from an uncaught exception.
I tried wrapping my call directly with a try-catch block but no luck. ( Also, all my code is running within the google test framework which also normally catches exceptions ). The only thing that seems to catch the exception is if I wrap the throw statement in a try block directly within the error callback.
Does anyone have any idea why this would happen and if there is a way to catch the exception?
When you interface with third-party libraries you usually have to catch all exception on the border between your code and their code:
int yourCallback( params )
{
try {
doStuff( params );
return Okay;
} catch (...) {
return Error;
}
}
The reason is you can't be sure that library is written in C++ or it uses the very same version of C++ runtime as your code uses.
Unless you're completely sure that code can deal with your exceptions you can't propagate exceptions to third-party code. The extreme example is COM where both your code and "other code" can be in whatever language and with whatever runtime and you are not allowed to let exceptions propagate through COM boundary.
Usually you should not throw exceptions "through" code you do not know anything about. It might be C code, which will not even clean up after itself.
How to deal with your concrete problem would require concrete information about the 3rd-party library you are interfacing with. What is that callback there for? To give you a chance to fix stuff? To inform you that an error occurred? Can you cancel whatever operation it is called from?
One way to deal with such a scenario is to store some information somewhere when the callback is called and check for that information when the actual processing finishes from your function that calls into that library.

Do c++ static libraries without mfc that are linked to an MFC project throw bad_alloc or CMemoryException*?

I'm working on a large, aging code base for an MFC app. The code has been worked on by many developers over time, and as a result, we have three different ways throughout the code of dealing with the possibility of an allocation failure with new.
The first way is to test for NULL on the result of new. We don't use nothrownew.obj so this is clearly an error that needs to be cleaned up.
The second is to catch CMemoryException* (yes, C++ exceptions are enabled in the compiler). From what I understand, MFC overrides the standard operator new, and throws this thing instead. I am fairly certain that this second method is correct in the MFC application itself. MFC overrides new, with its strange CMemoryException throwing version.
The last comes from our base of people who are good with C++, but aren't neccessarily MFC programmers. They are catching const std::bad_alloc&.
What I really don't know is what to expect for static libraries linked into the application. This is were the vast majority of the code that uses bad_alloc lives. Assuming these libraries are not compiled with MFC or ATL, and are written in standard C++ only, can they expect to catch bad_alloc? Or will the presence of MFC in the application they link to infect them with the global new operator and render their attempts to fail cleanly on a bad allocation moot?
If you have an answer, could you explain how this works, or point me to the right reference to sort this out?
It will depend on the compile options for the static libraries to be linked to the application.
If the libraries are compiled with a configuration to use the static Standard C++ run-time then I would expect the operator new from the Standard C++ run-time to be called.
If libraries are compiled with a configuration to use the Standard C++ run-time DLL then the resolution of these functions will be delayed until program load and should be resolved to the MFC replacements of operator new.
I also included a link to this Herb Sutter article regarding handle allocation errors that you may find useful.
Congratulations -- you seem to have stumped all of us. :-)
In theory, if MFC provides an overload for the global new function, then it should be used by all code in the program. But since the static libraries were compiled without knowing about that, I can't say for certain that it would.
The best I can suggest is to write some test code to find out. (I won't have access to my Windows system for the next few hours, or I'd do so myself and give you an answer.)
I've done some MFC-Code-Researches (in VC2010). Here are some facts.
The MFC throws a pointer to a global CMemoryException instance named "_simpleMemoryException" (see also AfxThrowMemoryException())
it is an CException whose m_bAutoDelete is false.
Idea: If it possible to change the c++-only-static-libraries, you can forward declare class CException; and/or class CMemoryException; into the root namespace.
Add a catch-block with catch (CMemoryException* pEx) {...} and/or catch (CException* pEx) {...} at each place where a std::bad_alloc-catch block is. Since the catched pointer is a pointer to a global object, it is not needed to call pEx->Delete();.
In this way the c++-only-static-libraries are not required to include afx.h or/and link against the MFC. I've tried it in VC2010, and it works fine. (only if RTTI is enabled, and only if nobody changes the MFC-NewHandler with AfxSetNewHandler to something else than the default-MFC-NewHandler AfxNewHandler)
You can change the MFC throwing behavior with AfxSetNewHandler(_PNH pfnNewHandler) and provide a pointer to your own NewHandler function. This function should then throw a std::bad_alloc exception.
But now the MFC-program-parts have the problem to catch a std::bad_alloc.