Ruby opaque pointer handling regression fix

This bug was introduced in swig-3.0.8 in #146252 adding shared_ptr
support. An ObjectPreviouslyDeleted error was incorrectly thrown
when the pointer was used as a parameter after being set to zero
via a call to 'DATA_PTR(self) = 0'.

It isn't clear to me which approach is better in this corner case,
so I've gone for backwards compatibility and restored the old behaviour.

Closes #602
This commit is contained in:
William S Fulton 2016-05-24 07:33:25 +01:00
commit 763827c2e1
5 changed files with 131 additions and 5 deletions

View file

@ -30,7 +30,8 @@ CPP_TEST_CASES = \
# stl_new
C_TEST_CASES += \
li_cstring
li_cstring \
ruby_manual_proxy \
include $(srcdir)/../common.mk

View file

@ -0,0 +1,49 @@
#!/usr/bin/env ruby
#
# The Subversion bindings use this manually written proxy class approach
# to the Ruby bindings. Note that in C the struct svn_fs_t is an
# opaque pointer and the Ruby FileSystem proxy class is hand written around it.
# This testcase tests this and the C close function and subsequent error
# handling.
require 'swig_assert'
require 'ruby_manual_proxy'
module Svn
module Fs
module_function
def create(path)
f = Ruby_manual_proxy::svn_fs_create(path)
return f
end
FileSystem = SWIG::TYPE_p_svn_fs_t
class FileSystem
class << self
def create(*args)
Fs.create(*args)
end
end
def path
Ruby_manual_proxy::svn_fs_path(self)
end
end
end
end
f = Svn::Fs::FileSystem.create("/tmp/myfile")
path = f.path
f.close
begin
# regression in swig-3.0.8 meant ObjectPreviouslyDeleted error was thrown instead
path = f.path
raise RuntimeError.new("IOError (1) not thrown")
rescue IOError
end
file = nil
begin
path = Ruby_manual_proxy::svn_fs_path(file)
raise RuntimeError.new("IOError (2) not thrown")
rescue IOError
end

View file

@ -0,0 +1,66 @@
%module ruby_manual_proxy
%typemap(in, numinputs=0) SWIGTYPE ** ($*1_ltype temp) "$1 = &temp;";
%typemap(argout) SWIGTYPE **OUTPARAM {
$result = SWIG_Ruby_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
}
%apply SWIGTYPE **OUTPARAM {
svn_fs_t **
};
%typemap(check) svn_fs_t * {
if (!$1) {
svn_swig_rb_raise_svn_fs_already_close();
}
}
%{
typedef struct svn_fs_t {
char path[256];
} svn_fs_t;
void svn_fs_create(svn_fs_t **fs_p, const char *path) {
svn_fs_t *fs = (svn_fs_t *)malloc(sizeof(svn_fs_t));
strncpy(fs->path, path, 256);
*fs_p = fs;
}
const char *svn_fs_path(svn_fs_t *fs) {
return fs->path;
}
%}
typedef struct svn_fs_t svn_fs_t;
void svn_fs_create(svn_fs_t **fs_p, const char *path);
const char *svn_fs_path(svn_fs_t *fs);
%{
static void svn_swig_rb_raise_svn_fs_already_close(void) {
rb_raise(rb_eIOError, "already closed");
}
static VALUE svn_fs_swig_rb_close(VALUE self) {
if (!DATA_PTR(self)) {
svn_swig_rb_raise_svn_fs_already_close();
}
DATA_PTR(self) = NULL;
return Qnil;
}
static VALUE svn_fs_swig_rb_closed(VALUE self) {
return DATA_PTR(self) ? Qfalse : Qtrue;
}
%}
%insert("init") %{
{
VALUE cSvnfs;
cSvnfs = rb_const_get(_mSWIG, rb_intern("TYPE_p_svn_fs_t"));
rb_define_method(cSvnfs, "close",
VALUEFUNC(svn_fs_swig_rb_close), 0);
}
%}