Discussion:
[Swig-devel] Automatic disown rationale
Albert Diserholt
2015-05-06 08:21:41 UTC
Permalink
Hi,

When wrapping C structure members, SWIG automatically sets the
"wrap:disown" attribute on pointers (cwrap.c:1411). This caused memory
leaks in my script, which wraps a library with constructs such as
these:

struct resp {
struct option1 *opt1;
struct option2 *opt2;
};

Functions in the library take a pointer to a resp struct, and the
caller (my script) is expected to allocate and manage memory for the
optional member pointers (option1 and option2). If my script is not
interested in option2, it sets it to NULL, and the library ignores it.

So, my question is: Why are member pointers automatically disowned? It
sounds counterintuitive to me to have it this way, and it was quite
hard to track down. Simplest way to work around this for me was to use
'sed' on the generated wrap file, which is very ugly. Perhaps a
feature could be introduce to disable the functionality, and not break
backwards compatibility?

Regards,
Albert
William S Fulton
2015-05-10 16:14:53 UTC
Permalink
Post by Albert Diserholt
Hi,
When wrapping C structure members, SWIG automatically sets the
"wrap:disown" attribute on pointers (cwrap.c:1411). This caused memory
leaks in my script, which wraps a library with constructs such as
struct resp {
struct option1 *opt1;
struct option2 *opt2;
};
Functions in the library take a pointer to a resp struct, and the
caller (my script) is expected to allocate and manage memory for the
optional member pointers (option1 and option2). If my script is not
interested in option2, it sets it to NULL, and the library ignores it.
So, my question is: Why are member pointers automatically disowned? It
sounds counterintuitive to me to have it this way, and it was quite
hard to track down.
I think this is to ensure that the default behaviour is not to seg
fault as the memory handling is tricky. A memory leak is preferable to
code crashing. Consider the following, where option1 is:

struct option1 {
int option;
};

and modifying the behaviour to what you want with the typemap shown at
the end of this email and Python code:

r = resp()
r.opt1 = option1()
r.opt1.option=123 # This seg faults

It seg faults on line 3 because Python will destroy the newly created
option1 after line 2 is finished and you can't use the destroyed
option1 struct on line 3.
Post by Albert Diserholt
Simplest way to work around this for me was to use
'sed' on the generated wrap file, which is very ugly. Perhaps a
feature could be introduce to disable the functionality, and not break
backwards compatibility?
If you ever are using sed on SWIG generated code, you are more than
likely doing the wrong thing. In this case, you would use a typemap to
change the default behaviour. This is the default typemap being used:

%typemap(in, noblock=1) SWIGTYPE *(void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp,$descriptor, $disown | %convertptr_flags);
if (!SWIG_IsOK(res)) {
%argument_fail(res, "$type", $symname, $argnum);
}
$1 = %reinterpret_cast(argp, $ltype);
}

There are lots of ways to apply typemaps (please read the docs) but
for opt1, you could simply use the following if you want the behaviour
you asked for:

%typemap(in, noblock=1) struct option1 *opt1(void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp,$descriptor, %convertptr_flags);
if (!SWIG_IsOK(res)) {
%argument_fail(res, "$type", $symname, $argnum);
}
$1 = %reinterpret_cast(argp, $ltype);
}

William
Albert Diserholt
2015-05-18 12:08:57 UTC
Permalink
Post by William S Fulton
Post by Albert Diserholt
Hi,
When wrapping C structure members, SWIG automatically sets the
"wrap:disown" attribute on pointers (cwrap.c:1411). This caused memory
leaks in my script, which wraps a library with constructs such as
struct resp {
struct option1 *opt1;
struct option2 *opt2;
};
Functions in the library take a pointer to a resp struct, and the
caller (my script) is expected to allocate and manage memory for the
optional member pointers (option1 and option2). If my script is not
interested in option2, it sets it to NULL, and the library ignores it.
So, my question is: Why are member pointers automatically disowned? It
sounds counterintuitive to me to have it this way, and it was quite
hard to track down.
I think this is to ensure that the default behaviour is not to seg
fault as the memory handling is tricky. A memory leak is preferable to
struct option1 {
int option;
};
and modifying the behaviour to what you want with the typemap shown at
r = resp()
r.opt1 = option1()
r.opt1.option=123 # This seg faults
It seg faults on line 3 because Python will destroy the newly created
option1 after line 2 is finished and you can't use the destroyed
option1 struct on line 3.
Post by Albert Diserholt
Simplest way to work around this for me was to use
'sed' on the generated wrap file, which is very ugly. Perhaps a
feature could be introduce to disable the functionality, and not break
backwards compatibility?
If you ever are using sed on SWIG generated code, you are more than
likely doing the wrong thing. In this case, you would use a typemap to
%typemap(in, noblock=1) SWIGTYPE *(void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp,$descriptor, $disown | %convertptr_flags);
if (!SWIG_IsOK(res)) {
%argument_fail(res, "$type", $symname, $argnum);
}
$1 = %reinterpret_cast(argp, $ltype);
}
There are lots of ways to apply typemaps (please read the docs) but
for opt1, you could simply use the following if you want the behaviour
%typemap(in, noblock=1) struct option1 *opt1(void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp,$descriptor, %convertptr_flags);
if (!SWIG_IsOK(res)) {
%argument_fail(res, "$type", $symname, $argnum);
}
$1 = %reinterpret_cast(argp, $ltype);
}
William
I see, and I agree with you. I'm using Lua, and I am not encountering
any seg faults when removing the disown and letting Lua's GC handle
the deallocation. The reference to the newly allocated object should
be in scope for the whole duration, at least in Lua. Perhaps the two
languages work differently?

I know how the default typemap is defined, but have found no way to
override it. I could define my own typemap and use %apply on the
applicable structure members, but since it is a big library and the
same pattern is used in many locations, I was looking for a better way
to disable something which didn't help me. I was mostly curious about
why the automatic disown was there.

Thanks.
Regards,
Albert
William S Fulton
2015-05-22 18:32:54 UTC
Permalink
Post by Albert Diserholt
I know how the default typemap is defined, but have found no way to
override it.
Read the typemap docs, you'll find ways to debug the typemaps being
used. The default typemap is probably SWIGTYPE * though, like in
Python.

William

Continue reading on narkive:
Search results for '[Swig-devel] Automatic disown rationale' (Questions and Answers)
15
replies
In your opinion, what makes a cult a cult?
started 2006-04-24 09:40:26 UTC
religion & spirituality
Loading...