Temporary C++ objects (created as "new local variables" in a typemap) do not get destroyed properly when SWIG_fail is used. In the generated wrapper, the "fail" label is incorrectly located in the same scope as the temporary variables. The SWIG_fail jumps to "fail:" which triggers SWIG_croak_null() which results in a Perl croak() which uses longjmp() to exit. Hence, the destructors for objects on the stack are never called and associated memory is leaked. A simple fix is to place the entire function contents (before the "fail" label) inside of a { } block, causing it to leave scope cleanly before croaking.
For example, use of the following typemap will cause temp_str to be leaked on a SWIG_fail.
%typemap(in) String (std::string temp_str) {
STRLEN temp_len = 0;
const char* temp_ptr;
temp_ptr = SvPV($input, temp_len);
temp_str.assign(temp_ptr, temp_len);
$1 = &temp_str;
}
Reproduced with current SWIG git master. Simple interface file:
Then:
This issue is specific to languages where whatever SWIG does on "fail" calls
longjmp
. It's pretty common that we set an exception via the target language's C API and then return a dummy value from our wrapper function in which case the C++ object should get destroyed OK.Sounds good. I did a quick test and this indeed does the trick.
I fixed this same issue for Lua in 9ab9c716239d2855bdd6c0771e2e980c0767fb57, and https://github.com/swig/swig/issues/1981 is the same but for Go.
There's a testcase exception_memory_leak for it so writing a
_runme.pl
for that would provide a regression test.