[postgis-users] Error handling: GEOS throws in PostGIS.

David Blasby dblasby at refractions.net
Fri Apr 11 15:26:26 PDT 2003


I'm having troubles trapping exceptions thrown by GEOS in postgresql.
My GEOS wrapper (postgis_geos_wrapper.cpp) looks like this:


// call g1->contains(g2)
// returns 0 = false
//         1 = true
//         2 = error was trapped
char GEOSrelateContains(Geometry *g1, Geometry*g2)
{
    try {
        bool result;
        result = g1->contains(g2);
        if (result)
            return 1;
        else
            return 0;
    }
    catch (...)
    {
        return 2;
    }
}

And in the .c PostGIS (postgis_geos.c):

// overlaps(GEOMETRY g1,GEOMETRY g2)
// returns  if GEOS::g1->overlaps(g2) returns true
// throws an error (elog(ERROR,...)) if GEOS throws an error
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));


    Geometry *g1,*g2;
    bool result;

    errorIfGeometryCollection(geom1,geom2);
    initGEOS(MAXIMUM_ALIGNOF);

    g1 =     POSTGIS2GEOS(geom1 );
    g2 =     POSTGIS2GEOS(geom2 );

    GEOSdeleteGeometry(g1);
    GEOSdeleteGeometry(g2);

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

    PG_RETURN_BOOL(result);
}


This works great in simple examples (like the test.c norman wrote).
But, when you have another layer of indirection - like with postgresql,
problems happen.  I think the problem is with postgresql loading a
C .so (postgis), which is linked to a C++ .so (GEOS).  Postgresql
is far removed from the GEOS error handling (in libc++).

Basically, as soon as "g1->contains(g2);" throws an error that leaves
the GEOS .so, postgresql dies immediately - the exception is not
catch so terminate() is called.

This doesnt happen if you are using GEOS in a c++ program, or using
a C++ wrapper for a C program. It only has problems with 3 levels
of indirection.

Others have had this problem - 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++.

The only solution I can find to this (apart from forcing people to
use a very up-to-date gcc/g++ and perhaps statically linking libc++ to
postgresql) is actually write the C wrapper as part of GEOS.

In order to test this, I modified GEOS so that GEOMETRY has a function:

 void Geometry::throw_exception()
 {
        throw "I see dead people!";
 }


If you call g->throw_exception() in the postgis geos wrapper, postgresql
will immediately die.  But, if you re-write it (still in GEOS) like:

 void Geometry::throw_exception()
 {
     try
     {
         cout << "in throw_exception() try block - about to throw an 
error"<<endl;
               throw "I see dead people!";
          }
          catch (...)
          {
              cout << "in throw_exception() - caught an error"<<endl;
              return;
          }
          // never get here
 }

You can successfully catch the error!


So, unless anyone has any bright ideas, we could think about putting a C 
api directly in GEOS.  If we use the standard C way of error handling 
(return an error code or NULL, like in the above), PostGIS should have 
no problems.  Unfortunately, this does
"pollute" GEOS.

What think?

dave




More information about the postgis-users mailing list