[geos-devel] Ruby, FFI and ERROR_/NOTICE_MESSAGE

J Smith dark.panda+lists at gmail.com
Wed Dec 8 23:50:18 EST 2010


Howdy list.

I've run into a problem with the Ruby FFI bindings[1] and was
wondering if anyone has hit onto this problem before or has any
advice.

The basic gist of it goes something like this: as far as I can tell,
it seems that the error/notice handling code in GEOS is giving Ruby
and/or FFI a conniption fit. This may well be due to how I'm using FFI
to handle exceptions, but I'm not entirely sure of an alternative.

The basic idea is that I'm calling initGEOS_r with callbacks to a
notice handler and an error handler. The notice handler does nothing
and just ignores any raised notices, while the error handler will
raise a RuntimeError with the error message.

In some cases, these exceptions lead to segfaults and other strange
memory errors. The errors are reproducible, although finding the
conditions required to create them can be difficult and the results
can vary each time they are run. The best example I have at the moment
is the following using Ruby 1.9.2 and the ffi gem version 1.0.1 on OSX:

 $: << '.'
 require 'lib/ffi-geos'

 2.times do
   wktr = Geos::WktReader.new
   begin
     g = wktr.read('POINT(gibberish)')
   rescue RuntimeError => e
     puts e
   end
   GC.start
end

During the second loop, this code will sometimes result in a segfault
while other times it will raise a Ruby exception from FFI along the
lines of

`GEOSWKTReader_read_r': method `call' called on hidden T_ARRAY object
(0x0000010284b298 flags=0xa007 klass=0x0) (NotImplementedError)

Garbage collection plays a role in the error as well -- removing the
GC.start line will cause the script to succeed. The number of loops
can also be increased, but the error, be it a segfault or a catchable
Ruby exception, will occur eventually once GC runs.

I believe that the crux of the problem may be due to GEOS's error
handlers using varargs, which libffi cannot handle in callbacks
according to its documentation. Many of the errors raised via
ERROR_MESSAGE in GEOS use an sprintf format string along with the
actual error, while others sometimes just return the error message
string as a single argument.

As a test, I patched the current svn trunk to allow the pointers
ERROR_MESSAGE and NOTICE_MESSAGE to be set to NULL (or nil in Ruby via
FFI) and wrapped all uses of them in checks for NULL. The segfaults
now go away in both Ruby 1.8.7 and 1.9.2, but this also means that the
error messages provided are gone, which kinda sucks.

I'm not aware of a solution to try Ruby- or FFI-wise, but if anybody
has any hints that would be awesome. Alternatively, would it be
possible to patch the CAPI to accommodate? I'm not overly familiar
with the CAPI code outside of some experimentation I've been doing
over the past few days, but perhaps it would be possible to have
alternative error handlers that don't use varargs and could instead
pass a definitive set of arguments to their callbacks or something?
Another alternative may be to store the most recent error message in
the context handle and have it retrievable through a function when needed.

Any suggestions or advice would be much appreciated. Thanks for reading, list!

Cheers!

J

[1] Source code available via https://github.com/dark-panda/ffi-geos


More information about the geos-devel mailing list