Wednesday, 11 March 2009

hijacking throw

Here's continuation about internals of g++ throw mechanism.

Recent post showed how to effectively detect any exception type at runtime. It lacked one important information - where was the exception thrown. Who have made this.

Who is responsible for "bad argument", "logic_error" or anything. Who? Who nows?

On g++ exceptions are raised using __cxa_throw call. This is is runtime call that given given exception object (and some stuff) starts searching for exception handler and starts unwinding stack. Eventually it aborts if no handler was found.

How about hijacking this call? In gnu tool chain it's easy. __cxa_throw resides in libstc++.so. Lazy linkage and dlopen permits us to ovoerride __cxa_throw and the load original version from appropriate libstdc++.so. Well look at source code:

#include <typeinfo>
#include <stdexcept>
#include <iostream>
#include <dlfcn.h>

typedef void (*cxa_throw_type)(void* , void *, void (*) (void *));
cxa_throw_type orig_cxa_throw = 0;

void load_orig_throw_code()
{
 void* orig_libcxx = dlopen("/usr/lib64/libstdc++.so.6", RTLD_LAZY);
 std::cerr << "loaded orig libc++ " << orig_libcxx<< "\n";
 orig_cxa_throw = (cxa_throw_type)( dlsym(orig_libcxx, "__cxa_throw") );
 std::cerr << "loaded orig_cxa_throw " << (void*)orig_cxa_throw << "\n";
 dlclose(orig_libcxx);
}

extern "C" 
void __cxa_throw(void *thrown_exception, void *pvtinfo, void (*dest) (void *) ) {
 std::type_info const* tinfo = reinterpret_cast<std::type_info const*>(pvtinfo); 
 std::cerr << "YEAH! detected throw of exception of " << tinfo->name()<< "\n";
 if( orig_cxa_throw == 0 )
  load_orig_throw_code();
 orig_cxa_throw(thrown_exception, pvtinfo, dest);
}

void foo() {
 std::cerr << "throwing exception\n";
 throw std::runtime_error("akuku");
}

int main()
{
 try { foo(); }
 catch(std::exception& e) {
  std::cerr << "exception successfully caught at main\n";
 }
 return 0;
}
Voila. The output:
$ ./hijack
loaded orig libc++ 0x2a95587000
loaded orig_cxa_throw 0x34e35af1a0
throwing exception
YEAH! detected throw of exception of St13runtime_error
exception successfully caught at main
How there are some problems and things to do:
  • how the hell should we know what is the path to libstdc++.so (it can't be hardcoded as in this proof-of-concept)
  • we must use backtrace and some "debug info" retriever to show where is the exception throws
  • initialization of orig_cxa_throw must be more safe

But for now it works at least on 32&64 bit linuxes. I've got to test in on some production code.

Tuesday, 10 March 2009

boost size

I acknowledge that Boost is a great library. Great interfaces, stability, design and what not. Great people behind ...

But think a little:

#include <boost/format.hpp>
using g++ and boost 1.37 yields literally
  • 147 includes
  • 15899 lines of source code!
  • 509257 bytes of source code!
Madness!