VC++ Exception Handling differ on x86 and x64 for IBPP / Firebird client - c++

I am hacking around with IBPP on Visual Studio 2015 / VC++. IBPP is a c++ wrapper for the firebird / interbase API.
IBPP, a C++ Client Interface to Firebird Server
Part of this package is a little test-suite, you may download it here:
ibpp-2-5-3-1-src.zip
To start with the test-suite you will find a simple batchfile to compile it under
x:...\ibpp-2-5-3-1-src\tests\vs2005\simplest-build.bat
It compiles fine with the native x86 and x64 toolchains of vc++ 2015.
Before compiling you need to edit lines 84 to 86 of
x:...\ibpp-2-5-3-1-src\tests\tests.cpp
const char* DbName = "x:/ibpptest/test.fdb"; // FDB extension (GDB is hacked by Windows Me/XP "System Restore")
const char* BkName = "x:/ibpptest/test.fbk";
const std::string ServerName = ""; //"localhost"; // Change to "" for local protocol / embedded
Please keep mind to create the directory x:\ibpptest\.
Furthermore you need to download the fblient files which are not available on its own but as part of the entire server archive. Get these both files:
32-bit Embedded
and
64-bit Embedded
.
For simplifying create two directories besides x:\...\ibpp-2-5-3-1-src\tests\vs2005\:
x:\...\ibpp-2-5-3-1-src\tests\vs2015x86\
x:\...\ibpp-2-5-3-1-src\tests\vs2015x84\
and copy x:\...\ibpp-2-5-3-1-src\tests\vs2005\simplest-build.bat into them. Now copy the fbclient files (32 Bit to x86, 64 Bit to x64) in these directories:
intl/*
udf/*
fbembed.dll
firebird.msg
ib_util.dll
icudt30.dll
icuin30.dll
icuuc30.dll
msvcp80.dll
msvcr80.dll
Now you can compile and start tests.exe. The x86 binary generates some errors in Test 6, that's OK because you are using the embedded version of the fblient files. The x64 binary will end up in a Windows program failure screen. This happens in Test3 when the test suite activates an exception:
try
{
#if defined(IBPP_WINDOWS) && defined(_DEBUG)
OutputDebugString(_("An exception will now get logged in the debugger: this is expected.\n"));
#endif
st1->ExecuteImmediate( "CREATE SYNTAX ERROR(X, Y) AS "
"SELECT ERRONEOUS FROM MUSTFAIL M" );
}
catch(IBPP::SQLException& e)
{
//~ std::cout<< e.what();
if (e.EngineCode() != 335544569)
{
_Success = false;
printf(_("The error code returned by the engine during a\n"
"voluntary statement syntax error is unexpected.\n"));
}
}
In the x86 binary this exception was caught as expected but in the x64 binary it will not. Does anybody knows how to achive similar exception handeling in the x64 binary?
Thanks in advance for any help!

Caveat: I used the Visual Studio 2017 environment to run the simplest-build.bat file.
It appears from the evidence I provide below that there is a fork or other compiling difference between the 32 bit and 64 bit versions of the Firebird service that causes this problem.
Solution: The EngineCode() member function does not exist in the 64 bit version. You must use the exception's what() member function as shown in the commented out line inside the Test3() catch block. If you desire to use EngineCode information you will have to parse it out of the what() string, because that contains all of the information that was originally provided as individual data members in the IBPP::SQLExceptionImpl class for 32 bit.
try
{
#if defined(IBPP_WINDOWS) && defined(_DEBUG)
OutputDebugString(_("An exception will now get logged in the debugger: this is expected.\n"));
#endif
st1->ExecuteImmediate( "CREATE SYNTAX ERROR(X, Y) AS "
"SELECT ERRONEOUS FROM MUSTFAIL M" );
}
catch(IBPP::SQLException& e)
{
//~ std::cout<< e.what();
printf(e.what());
//if (e.EngineCode() != 335544569)
//{
// _Success = false;
// printf(_("The error code returned by the engine during a\n"
// "voluntary statement syntax error is unexpected.\n"));
//}
}
Result of what() call.
*** IBPP::SQLException ***
Context: Statement::ExecuteImmediate( CREATE SYNTAX ERROR(X, Y) AS SELECT ERRONEOUS FROM MUSTFAIL M )
Message: isc_dsql_execute_immediate failed
SQL Message : -104
can't format message 13:896 -- message file C:\WINDOWS\SYSTEM32\firebird.msg not found
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 1, column 8
SYNTAX
Puzzle: statement.cpp shows the use of IBPP::SQLExceptionImpl and other ...ExceptionImpl usage, so I have to believe this source code is the 32 bit branch. If this is supposed to be a common branch for both 32 and 64 bit, then I don't see how it can work.
There are two header files that define exception classes. I believe that _ibbp.h was used to compile the 32 bit client and ibbp.h was used for the 64 bit client. I came to these conclusions by changing the catch clause in Test3() to see what possible exceptions could be happening. The ...ExceptionImpl classes would only compile with the 32 bit client dlls and they would not compile with the 64 bit dlls.
From _ibpp.h (32bit fbclient dlls recognize these classes. 64bit fbclient dlls do not.)
///////////////////////////////////////////////////////////////////////////////
//
// Implementation of the "hidden" classes associated with their public
// counterparts. Their private data and methods can freely change without
// breaking the compatibility of the DLL. If they receive new public methods,
// and those methods are reflected in the public class, then the compatibility
// is broken.
//
///////////////////////////////////////////////////////////////////////////////
//
// Hidden implementation of Exception classes.
//
/*
std::exception
|
IBPP::Exception
/ \
/ \
IBPP::LogicException ExceptionBase IBPP::SQLException
| \ / | \ /
| LogicExceptionImpl | SQLExceptionImpl
| |
IBPP::WrongType |
\ |
IBPP::WrongTypeImpl
*/
From ibpp.h (both fbclient dll sets recognize these classes)
/* IBPP never return any error codes. It throws exceptions.
* On database engine reported errors, an IBPP::SQLException is thrown.
* In all other cases, IBPP throws IBPP::LogicException.
* Also note that the runtime and the language might also throw exceptions
* while executing some IBPP methods. A failing new operator will throw
* std::bad_alloc, IBPP does nothing to alter the standard behaviour.
*
* std::exception
* |
* IBPP::Exception
* / \
* IBPP::LogicException IBPP::SQLException
* |
* IBPP::WrongType
*/
In all of tests.cpp, the only catch for IBPP::SQLException is in Test3(). Every other catch uses IBPP::Exception.
So this problem will only show up in Test3() when compiling for 64 bit, but I think it would manifest itself whenever IBPP::SQLException is used in a 64 bit implementation.

After a lot of more research I found the cause. I was wrong beliving that the exception handling in x86 and x64 differ. The IBPP library contains a bug (since 10 years!) which only happens in the x64/windows szenario when the firebird library reports an (complex) error condition to the caller.
So what happens is:
The test programm calls the IBPP libarary. The IBPP library calls the firebird API / library. The firebird library reports its results of calls in a array[20] of longs, they call it "ISC_STATUS vector". The IBPP library checks this results and in a case of an error it throws an exception. The test program catches such exceptions and reports them to the use.
So far, so good. But the bug is, that IBPP defines ISC_STATUS as an array[20] of longs as firebird it also did until v2.0 - which only support x86 windows. Beginning with v2.1 firebird supports x64 windows an defines ISC_STATUS as an array of intptr_t which leads to "long long" on windows x64 LLP64 compilers and to long on LP64 linux compilers - both are 64 bit wide. On ILP32 windows and linux x86 compilers intptr_t is 32 bit wide.
IBPP doesn't closed the gap to firebird and stays on its definition of ISC_STATUS as long - which leads to a 32 bit wide data type on LLP64 windows x64 systems (but to 64 bit on linux, as gcc on linux uses a LP64 system, so the bug only happens on windows).
So the firebird x64 API reports up to 20 status integers to the "by reference parameter" array[20] of 64 Bit integers. The FBPP library passes an array[20] of 32 Bit integers. When the firebird API stores values in second half of the array it overwrites memory of the caller. In this case the next bytes after the ISC_STATUS vector are occupied by a c++ string object. Both, the status array and the string a part of the IBS (interbase status) class. Many of the IBPP functions often instantiating a local object of this class to manage the firebird API results and a error descriping string. When the functions exits the framework cleans up such local objects and tries to free the string but its metadata in memory was overwritten by the firebird API.
So the cleanup of the local IBS object leads to an unknown software exceptions which overdrives the exceptions thrown by the IBPP framework. And this exception is not catched by the test program but by windows / dr. watson.
I fixed the definition of ISC_STATUS from "long" to "intptr_t" and all works as expected.
Thank you all for your hints.

Related

I switched my project to x64 and got an error

I have this project that I'm working on for a while now, and it was working just fine before I switched from releasing an x86 version to an x64 one.
This is the line of code where the error appeared:
ReadProcessMemory(a.hProcess, LPCVOID(b->Ebx + 8), LPVOID(&c), 4, 0);
I don't understand assembly but when the Error appeared at b->Ebx I changed it to b->Rbx. and it compiled and run but it didn't do the job it was supposed to do.
Am I using the wrong register?
After a little bit of debugging
pe_dos_h = PIMAGE_DOS_HEADER(pe_image);
pe_nt_h = PIMAGE_NT_HEADERS(DWORD(pe_image) + pe_dos_h->e_lfanew);
//error when trying to assign a value or access the signature in nt-headers
//ERROR: read access violation
IMAGE_NT_HEADERS* pe_nt_h->Signature == IMAGE_NT_SIGNATURE;//0x00004550-PE00
The pe_image is raw data copied from a PE(.exe) file. Is the difference is in handling x86 PE image vs x64 one?
This is a simplified version of the code. If you think the problem is out of the scope of this piece of code let me know.
The problem was in the way I was defining the IMAGE_SECTION_HEADER, In x64 architecture, I had to use the x64-specific datatype IMAGE_SECTION_HEADER64.
and also when casting pe_nt_h = PIMAGE_NT_HEADERS(DWORD_PTR(pe_image) + pe_dos_h->e_lfanew);
I had to use DWORD_PTR instead of just DWORD because it was missing some bits.
here is the solution code for the simplified version I provided in the post:
PIMAGE_DOS_HEADER pe_dos_h = PIMAGE_DOS_HEADER(pe_image);
PIMAGE_NT_HEADERS64 pe_nt_h = PIMAGE_NT_HEADERS(DWORD_PTR(pe_image) + pe_dos_h->e_lfanew);

Several Nt functions return STATUS_WAIT_0 on Windows 7 x32

I have downloaded a Windows 7 x32 Enterprise (IE11) hyper-v image from Microsoft website to test a research project.
For some reason all the Ntdll functions I call (syscall) return STATUS_WAIT_0. I mean all of them that I have tested including RtlGetVersion, NtAllocateVirtualMemory, NtCreateFile and more.
Could this be because it's a virtual machine ? Or could it be because I do direct system calls ?
Please advise, I have tested my project under non-virtual machines including latest Windows 10 and it works fine so I doubt it's my code.
Update:
STATUS_WAIT_0 can be considered as STATUS_SUCCESS since it's value is both 0.
Ntdll function basically returns a NTSTATUS, like RtlGetVersion,NtAllocateVirtualMemory,NtCreateFile and more.
The following document contains the common usage details of the NTSTATUS values
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
Return value/code:
0x00000000
STATUS_SUCCESS/STATUS_WAIT_0
Description:
The operation completed successfully.
The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.

static lib call error: Exception: "A null reference pointer was passed to the stub." (using winsock2 Win32)

I created a windows-console application that works fine but trying to use Winsock2 (Ws2_32.lib) in another static-library (as part of a larger project) throws an exception.
The code compiles fine and the exe runs all is well, calls to WSAStartup() and gethostbyname() work as expected but then calling gethostbyname()
causes :
First-chance exception at 0x76e1c41f in TestApp.exe: 0x000006F4: A null reference pointer was passed to the stub.
which leads to:
First-chance exception at 0x7505cd99 (rpcrt4.dll) in TestApp.exe: 0xC0020043: An internal error occurred in RPC.
Ive double checked the calling code is the same and checked that the correct versions of the *.h *.dll and *.lib are being used by the linker - as far as i can tell they are.
I've compared the project settings for the two apps and cant see anything out of the ordinary.
Ive also made sure that all the libraries in the Project are using the same Character-Set.
[EDIT : chages after discovering the difference in the two apps is just the debugger exceptions being turned on or not ]
I can continue past the exceptions and the code appears to run, but I no longer have valid debugging symbols in the function. It isnt a crash but of course id rather not have the exceptions every time I call the function - I can obviously turn the exception-breaks off but aren't they there to tell me something is wrong ?
I am currently trying to get the up-to-date symbols for the ws2_32.lib and other modules from the MSDN symbol server / SymChk.exe
[EDIT 2 - finally got symbols for the stack]
> rpcrt4.dll!_NdrClientCall2() + 0x301 bytes
FWPUCLNT.DLL!_FwppProxyEngineOpen#24() + 0x19 bytes
FWPUCLNT.DLL!_FwppSessionCreate#20() + 0xd1 bytes
FWPUCLNT.DLL!_FwpmEngineOpen0#20() + 0x29 bytes
FWPUCLNT.DLL!_FwpIsNameCacheEnabledForProcess#4() + 0x7778 bytes
FWPUCLNT.DLL!_FwpmProcessNameResolutionEvent0#16() + 0x74 bytes
FWPUCLNT.DLL!_NamespaceCallout#12() + 0x72 bytes
ws2_32.dll!PrepareNamespaceCalloutBlob() + 0x153 bytes
ws2_32.dll!getxyDataEnt() + 0x74a7 bytes
ws2_32.dll!_gethostbyname#4() + 0xe7 bytes
I was getting this exception "0x000006F4: A null reference pointer was passed to the stub."
Turns out disabling my 3rd party firewall stopped the exception being thrown. Perhaps the firewall is intercepting the request and messing something up.
Might be worth a try for you :)

oracle::occi::ResultSet::next() crashes my program

I have a 64 bits C++ server application running on windows 7 and when it does a select on the database and calls next() on the result set the process simply dies, no exceptions, no dumps and no debug info after ResultSet->next(). Writes on the database works with no problems and both reads and writes works on the 32 bit version
I'm using the 11.2 version of the win64 oracle libraries that came with instant client and SDK
EDIT: it's the simplest of codes
const std::string sql("select * from schedule_import");
std::auto_ptr<IRecordSet> query = m_conn->Open(sql);
while(query->Next()) // dies
{
const std::string key(query->GetField("bean_key"));
//...
IRecordSet is just an interface for common functions of DB drivers like next, getField and it's implemented in here
bool OracleRecordSet::Next()
{
return m_pResultSet->next() != NULL; //crashes here
}
where m_pResultSet is a oracle::occi::ResultSet*
I'm not familiared with Oracle API, but question is if m_pResultSet is not NULL (in case of segmentation fault) and if there is no exception (in case of abort(), raise() stack).
BR!
After a lot of trys my problem is solved.
I was linking my debug program to oraocci11.lib because I didn't have the debug version and I thought it didn't matter much. After a bit of search I've found the debug version of the library, oraocci11d.lib, with the corresponding dll and the crash is gone

Program crashes with 0xC000000D and no exceptions - how do I debug it?

I have a Visual C++ 9 Win32 application that uses a third-party library. When a function from that library is called with a certain set of parameters the program crashes with "exception code 0xC000000D".
I tried to attach Visual Studio debugger - no exceptions are thrown (neither C++ nor structured like access violations) and terminate() is not called either. Still the program just ends silently.
How does it happen that the program just ends abnormally but without stopping in the debugger? How can I localize the problem?
That's STATUS_INVALID_PARAMETER, use WinDbg to track down who threw it (i.e. attach WinDbg, sxe eh then g.
Other answers and comments to the question helped a lot. Here's what I did.
I notices that if I run the program under Visual Studio debugger it just ends silently, but if I run it without debugger it crashes with a message box (usual Windows message box saying that I lost my unsaved data and everyone is sooo sorry).
So I started the program wihtout debugger, let it crash and then - while the message box was still there - attached the debugger and hit "Break". Here's the call stack:
ntdll.dll!_KiFastSystemCallRet#0()
ntdll.dll!_ZwWaitForMultipleObjects#20() + 0xc bytes
kernel32.dll!_WaitForMultipleObjectsEx#20() - 0x48 bytes
kernel32.dll!_WaitForMultipleObjects#16() + 0x18 bytes
faultrep.dll!StartDWException() + 0x5df bytes
faultrep.dll!ReportFault() + 0x533 bytes
kernel32.dll!_UnhandledExceptionFilter#4() + 0x55c bytes
//SomeThirdPartyLibraryFunctionAddress
//SomeThirdPartyLibraryFunctionAddress
//SomeThirdPartyLibraryFunctionAddress
//SomeThirdPartyLibraryFunctionAddress
//OurCodeInvokingThirdPartyLibraryCode
so obviously that's some problem inside the trird-party library. According to MSDN, UnhandledExceptionFilter() is called in fatal situations and clearly the call is done because of some problem in the library code. So we'll try to work the problem out with the library vendor first.
If you don't have source and debugging information for your 3rd party library, you will not be able to step into it with the debugger. As I see it, your choices are;
Put together a simple test case illustrating the crash and send it onto the library developer
Wrap that library function in your own code that checks for illegal parameters and throw an exception / return an error code when they are passed by your own application
Rewrite the parts of the library that do not work or use an alternative
Very difficult to fix code that is provided as object only
Edit You might also be able to exit more gracefully using __try __finally around your main message loop, something like
int CMyApp::Run()
{
__try
{
int i = CWinApp::Run();
m_Exitok = MAGIC_EXIT_NO;
return i;
}
__finally
{
if (m_Exitok != MAGIC_EXIT_NO)
FaultHandler();
}
}