Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions Examples/test-suite/go/exception_memory_leak_runme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import "strings"
import . "swigtests/exception_memory_leak"

func main() {
a := NewFoo()
if FooGet_count() != 1 {
panic("Foo count not 1")
}
b := NewFoo()
if FooGet_count() != 2 {
panic("Foo count not 2")
}

// Normal behaviour
Trigger_internal_swig_exception("no problem", a)
if FooGet_count() != 2 {
panic("Foo count not 2")
}
if FooGet_freearg_count() != 1 {
panic("Foo count not 1")
}

// SWIG exception triggered and handled (return new object case)
func() {
defer func() {
e := recover()
if strings.Index(e.(string), "Let's") != 0 {
panic(e.(string))
}
}()
Trigger_internal_swig_exception("null", b)
panic("Trigger_internal_swig_exception didn't panic")
}()
if FooGet_count() != 2 {
panic("Foo count not 2")
}
if FooGet_freearg_count() != 2 {
panic("Foo count not 2")
}

// SWIG exception triggered and handled (return by value case).
func() {
defer func() {
e := recover()
if strings.Index(e.(string), "Let's") != 0 {
panic(e.(string))
}
}()
Trigger_internal_swig_exception("null")
panic("Trigger_internal_swig_exception didn't panic")
}()
if FooGet_count() != 2 {
panic("Foo count not 2")
}
}
6 changes: 5 additions & 1 deletion Lib/go/goruntime.swg
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,15 @@ extern void _cgo_panic(const char *);
#endif

#define _swig_goallocate _cgo_allocate
#define _swig_gopanic _cgo_panic
#define _swig_gopanic_impl _cgo_panic
%}

#endif

%{
#define _swig_gopanic(M) do { _swig_gopanic_message = (M); goto fail; } while (0)
%}

#ifndef SWIGGO_GCCGO

%go_import("unsafe", _ "runtime/cgo")
Expand Down
50 changes: 38 additions & 12 deletions Source/Modules/go.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ class GO:public Language {
Printv(f_c_begin, " \"C\"\n", NULL);
Printv(f_c_begin, "#endif\n", NULL);
Printv(f_c_begin, " void cgo_panic_", unique_id, "(const char*);\n", NULL);
Printv(f_c_begin, "static void _swig_gopanic(const char *p) {\n", NULL);
Printv(f_c_begin, "static void _swig_gopanic_impl(const char *p) {\n", NULL);
Printv(f_c_begin, " cgo_panic_", unique_id, "(p);\n", NULL);
Printv(f_c_begin, "}\n\n", NULL);
}
Expand Down Expand Up @@ -1483,17 +1483,30 @@ class GO:public Language {
String *ct = gcCTypeForGoValue(info->n, info->result, fnname);
Printv(f->def, ct, NULL);
Delete(ct);

String *ln = NewString("_swig_go_result");
ct = gcCTypeForGoValue(info->n, info->result, ln);
Wrapper_add_local(f, "_swig_go_result", ct);
Delete(ct);
Delete(ln);
}

Delete(fnname);

Printv(f->def, " {\n", NULL);
// SWIG_fail in Go leads to a call to _swig_gopanic() which calls _cgopanic
// which calls longjmp() which means the destructors of any live
// function-local C++ objects won't get run. To avoid this happening, we
// wrap almost everything in the function in a block, and end that right
// before _swig_gopanic() at which point those destructors will get called.
//
// We need to add the code for these variables directly rather than using
// Wrapper_add_local() so that they exist outside the extra block we add
// under CPlusPlus to ensure local objects get destroyed if we exit via a
// panic.
Append(f->def, "const char * SWIGUNUSED _swig_gopanic_message = NULL;\n");
if (SwigType_type(info->result) != T_VOID) {
String *ln = NewString("_swig_go_result");
String *ct = gcCTypeForGoValue(info->n, info->result, ln);
Printv(f->def, ct, ";\n", NIL);
Delete(ct);
Delete(ln);
}
if (CPlusPlus) Append(f->def, "\n{");

// Apply the in typemaps.

Expand Down Expand Up @@ -1530,13 +1543,25 @@ class GO:public Language {

argout(parms, f);

cleanupFunction(info->n, f, parms);
String *cleanup = cleanupFunction(info->n, f, parms);

if (SwigType_type(info->result) != T_VOID) {
Printv(f->code, "\treturn _swig_go_result;\n", NULL);
Printv(f->code, "\treturn _swig_go_result;\n", NIL);
} else {
Printv(f->code, "\treturn;\n", NIL);
}

Printv(f->code, "}\n", NULL);
// add the failure cleanup code:
Printv(f->code, "\nfail: SWIGUNUSED;\n", cleanup, NIL);
Delete(cleanup);
if (CPlusPlus) Append(f->code, "}\n");
Printv(f->code, "_swig_gopanic_impl(_swig_gopanic_message);\n", NIL);
// _swig_gopanic() calls longjmp() but we need a dummy return to avoid
// compiler warnings.
if (SwigType_type(info->result) != T_VOID) {
Printv(f->code, "\treturn _swig_go_result;\n", NIL);
}
Printv(f->code, "}\n", NIL);

Wrapper_print(f, f_c_wrappers);

Expand Down Expand Up @@ -1757,7 +1782,7 @@ class GO:public Language {
* Final function cleanup code.
* ----------------------------------------------------------------------- */

void cleanupFunction(Node *n, Wrapper *f, ParmList *parms) {
String *cleanupFunction(Node *n, Wrapper *f, ParmList *parms) {
String *cleanup = freearg(parms);
Printv(f->code, cleanup, NULL);

Expand All @@ -1770,7 +1795,6 @@ class GO:public Language {
}

Replaceall(f->code, "$cleanup", cleanup);
Delete(cleanup);

/* See if there is any return cleanup code */
String *tm;
Expand All @@ -1780,6 +1804,8 @@ class GO:public Language {
}

Replaceall(f->code, "$symname", Getattr(n, "sym:name"));

return cleanup;
}

/* -----------------------------------------------------------------------
Expand Down