Files
raven/testdata/native_loader/cxx_exceptions_client.cpp

129 lines
2.3 KiB
C++

// C++ exceptions as the Microsoft compiler emits them, against the system msvcrt.dll: a catch by reference, a catch by value through the
// copy constructor, a rethrow caught in the same function and in the caller, catch(...), a new exception thrown from a catch block, and
// the destructors of the locals the exceptions leave. Built for both widths; the entry returns the number of the first check that failed.
// The table every type descriptor points to, which a program links statically as the Microsoft libraries do.
extern "C" const void *const type_info_table[1] __asm__("??_7type_info@@6B@") = {nullptr};
static int guards, destroyed;
struct Failure {
int value;
explicit Failure(int value) : value(value) {}
Failure(const Failure &other) : value(other.value + 100) {}
~Failure() { ++destroyed; }
};
struct Guard {
~Guard() { ++guards; }
};
__declspec(noinline) void thrower(int value)
{
Guard guard;
if (value)
throw Failure(value);
}
__declspec(noinline) int by_reference()
{
try {
thrower(7);
} catch (Failure &failure) {
return failure.value;
}
return -1;
}
__declspec(noinline) int by_value()
{
try {
thrower(3);
} catch (int) {
return -1;
} catch (Failure failure) {
return failure.value;
}
return -2;
}
__declspec(noinline) int rethrown()
{
try {
try {
thrower(1);
} catch (Failure &) {
throw;
}
} catch (Failure &failure) {
return failure.value;
}
return -1;
}
__declspec(noinline) int anything()
{
try {
throw 42;
} catch (...) {
return 5;
}
return -1;
}
__declspec(noinline) void passes_on()
{
Guard guard;
try {
thrower(9);
} catch (Failure &) {
throw;
}
}
__declspec(noinline) int caller_catches()
{
try {
passes_on();
} catch (Failure &failure) {
return failure.value;
}
return -1;
}
__declspec(noinline) int replaced()
{
try {
try {
thrower(2);
} catch (Failure &) {
throw 17;
}
} catch (int value) {
return value;
}
return -1;
}
extern "C" int raven_entry()
{
if (by_reference() != 7)
return 1;
if (by_value() != 103)
return 2;
if (rethrown() != 1)
return 3;
if (anything() != 5)
return 4;
if (caller_catches() != 9)
return 5;
if (replaced() != 17)
return 6;
// One guard in each call that threw, and the one of passes_on, which the rethrow left.
if (guards != 6)
return 7;
if (destroyed < 3)
return 8;
return 0;
}