backend dies when C function calls C++ library that throws an exception

Started by David Blasbyabout 23 years ago2 messageshackers
Jump to latest
#1David Blasby
dblasby@refractions.net

PostGIS (open source spatial objects for postgresql -
http://postgis.refractions.net ) is trying to integrate a C++ geometry
package (GEOS - Geometry Engine, Open Source -
http://geos.refractions.net ).

We are having trouble trapping exceptions thrown by the GEOS C++
library. The library isworking very well in general, but when GEOS
raises an exception that tries to leave the GEOS .so library, postgresql
immediately dies (signal 6 - ABORT).

The postgis library is a set of custom functions that are called by
postgresql using the standard API. These postgis functions call
functions in the GEOS library.

Basically, the layout is like:

postgis_geos.c -- gets merged into postgis.so which is loaded and used
by directly by postgresql.
postgis_geos_wrapper.cpp -- also merges into postgis.so, but handles
calls to the GEOS c++ library.
libgeos.so --- geos library

In postgis_geos.c ,the only interesting line is "result =
GEOSrelateOverlaps(g1,g2);" which calls a c++ wrapper function (see below).

PG_FUNCTION_INFO_V1(overlaps);
Datum overlaps(PG_FUNCTION_ARGS)
{
GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));

...

result = GEOSrelateOverlaps(g1,g2);
if (result == 2)
{
elog(ERROR,"GEOS overlaps() threw an error!");
PG_RETURN_NULL(); //never get here
}

PG_RETURN_BOOL(result);
}

postgis_geos_wrapper.cpp - this also get merged into postgis.so - it
handles calling GEOS.

//extern "C" GEOSrelateContains(Geometry *g1, Geometry*g2);
char GEOSrelateContains(Geometry *g1, Geometry*g2)
{
try {
bool result;
result = g1->contains(g2);
if (result)
return 1;
else
return 0;
}
catch (...)
{
return 2;
}
}

In general, this "wrapping" works fine - I've left out a bunch of
details, but things work *great* in postgresql as long as GEOS doesnt
throw any exceptions.
I can write stand alone C programs that handle the exceptions properly.

Its only has problems when there's three levels of indirection
(postgresql->postgis wrapper->GEOS).

If you write a C (or C++) program that uses the wrapper, everything
works fine.

Others have had similiar problems - for example people writing PERL
modules that use the perl "C" api to call C++ libraries. People doing
the same with PYTHON have also had problems. The only technical
reference I can find is at:
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=37933

Basically, there's a problem if libc is loaded before libc++ because the
exception handler isnt installed (or some such thing).

Anyone have any ideas of what to do about this?

dave blasby
dblasby@refractions.net

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Blasby (#1)
Re: backend dies when C function calls C++ library that throws an exception

David Blasby <dblasby@refractions.net> writes:

We are having trouble trapping exceptions thrown by the GEOS C++
library. The library isworking very well in general, but when GEOS
raises an exception that tries to leave the GEOS .so library, postgresql
immediately dies (signal 6 - ABORT).

The redhat bugzilla entry you reference suggests that this should work
in Linux, given compatible (and recent) versions of gcc/glibc/glibc++.
Are you up to date on those?

But if you want a general cross-platform solution, you may be out of
luck. Since there is no C++ library in the standard backend, there
is nothing that would know to set up the C++ exception stack.

(It occurs to me that if it's still failing for you on recent Linux
releases, it might be because your code and GEOS are in separate shared
libs that can't even agree on a common location of the C++ exception
stack pointers.)

The only workaround I can think of is to build a nonstandard postgres
executable that contains libc++ as part of the main executable.

regards, tom lane