Travis Vitek wrote:
I'm working on fixing an issue with test 19.exceptions.mt.cpp on AIX. The
issue is that the test spins in a loop because the loop counter is being
thrashed when an exception is copied onto the stack. Here is a simple
testcase.
#include <exception>
void test_single_exception ()
{
for (int i = 0; i < 5; ++i) {
try {
throw std::exception ();
}
catch (std::exception ex) {
&ex;
}
}
}
int main ()
{
test_single_exception ();
return 0;
}
So the issue is actually not that complicated. The exception type provided
by STDCXX is 4 bytes in size, and the native one is 8.
Yikes! That's very bad!
In and of itself,
that shouldn't really be a problem because the two definitions should never
coexist, right?
Unfortunately, they do. All the exceptions thrown by the runtime
(bad_alloc, bad_cast, bad_exception, and bad_typeid) derive from
std::exception. So the runtime has one view of the exception
objects it throws but a program that uses stdcxx sees them
differently.
So the problem really shows up when the config tests run,
they set the following macros...
#define _RWSTD_NO_EXCEPTION_ASSIGNMENT
// #define _RWSTD_NO_EXCEPTION_COPY_CTOR
#define _RWSTD_NO_EXCEPTION_DEFAULT_CTOR
#define _RWSTD_NO_EXCEPTION_DTOR
#define _RWSTD_NO_EXCEPTION_WHAT
If I'm reading the code correctly, this means that STDCXX will provide
definitions for the default ctor, copy-assignment operator, dtor and what().
Right.
The definition of the copy-ctor will come from somewhere else [where?].
From the xlC runtime library, libC.a.
Anyways, an exception is created and copied out for the unwind. The
exception is then copied back onto the stack at the location the exception
is handled. The code that actually copies the exception expects the object
to be 8 bytes in size, but the code that created the exception only
allocates 4 bytes for it.
So here is my problem with all of this. How is this safe?
It's not. It's a serious bug in our library. Somehow we're missing
a data member in std::exception that the xlC runtime library defines.
If the one of the
'special' functions provided by the system has some side effect, and we use
that implementation, then how can we safely define any of the other
'special' functions?
The assumption/hope is that the functions are straightforward and
have no side-effects.
That said, what is the appropriate solution? Should we just pad the type out
to the correct size,
Yes. As Farid says, the XLC exception and ours must have the same
size.
or should we provide our own definition of the copy
ctor, possibly looking at the compiler test to verify it is not wrong. Both
seem to work quite well, but I'm afraid I don't understand why we opt to use
the definitions of the 'special' functions that are provided. I guess I
would understand if I had got a linker error complaining of mulitply defined
symbols, but I don't.
This (the interface between the language runtime and the library)
is the most difficult area of the library for independent library
authors like us to get right. We can't help but make assumptions
about the runtime. Some are based on our inspection of the native
library headers (which may change in subtle but sometimes
important ways from one release to another), others we try to
automate (the detection of the special member functions of the
exception classes). Both approaches are fraught with peril.
Martin