diff --git a/CHANGES.current b/CHANGES.current index af6707824..5b572e04f 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,13 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.9 (in progress) =========================== +2016-05-14: wsfulton + Fix #434 - Passing classes by value as parameters in director methods did not create + a copy of the argument leading to invalid memory accesses if the object was used + after the upcall into the target language. Passing arguments by value shouldn't give + rise to these sorts of memory problems and so the objects are now copied and ownership + of their lifetime is controlled by the target language. + 2016-05-07: wsfulton Fix #611. Fix assertion handling defaultargs when using %extend for a template class and the extended methods contain default arguments. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index ddcdc658b..efece0066 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -174,7 +174,6 @@ CPP_TEST_CASES += \ director_abstract \ director_alternating \ director_basic \ - director_property \ director_binary_string \ director_classes \ director_classic \ @@ -189,12 +188,14 @@ CPP_TEST_CASES += \ director_ignore \ director_keywords \ director_namespace_clash \ + director_nested \ director_nspace \ director_nspace_director_name_collision \ - director_nested \ director_overload \ director_overload2 \ + director_pass_by_value \ director_primitives \ + director_property \ director_protected \ director_protected_overloaded \ director_redefined \ diff --git a/Examples/test-suite/csharp/director_pass_by_value_runme.cs b/Examples/test-suite/csharp/director_pass_by_value_runme.cs new file mode 100644 index 000000000..ba6371590 --- /dev/null +++ b/Examples/test-suite/csharp/director_pass_by_value_runme.cs @@ -0,0 +1,43 @@ +using System; +using director_pass_by_valueNamespace; + +public class runme +{ + private static void WaitForGC() + { + System.GC.Collect(); + System.GC.WaitForPendingFinalizers(); + System.Threading.Thread.Sleep(10); + } + + static void Main() + { + runme r = new runme(); + r.run(); + } + + void run() + { + Caller caller = new Caller(); + caller.call_virtualMethod(new director_pass_by_value_Derived()); + { + int countdown = 5; + while (true) { + WaitForGC(); + if (--countdown == 0) + break; + }; + } + // bug was the passByVal 'global' object was destroyed after the call to virtualMethod had finished. + int ret = runme.passByVal.getVal(); + if (ret != 0x12345678) + throw new Exception("Bad return value, got " + ret.ToString("x")); + } + public static PassedByValue passByVal; +} + +class director_pass_by_value_Derived : DirectorPassByValueAbstractBase { + public override void virtualMethod(PassedByValue pbv) { + runme.passByVal = pbv; + } +} diff --git a/Examples/test-suite/director_pass_by_value.i b/Examples/test-suite/director_pass_by_value.i new file mode 100644 index 000000000..31d8ce2d2 --- /dev/null +++ b/Examples/test-suite/director_pass_by_value.i @@ -0,0 +1,30 @@ +%module(directors="1") director_pass_by_value +%director DirectorPassByValueAbstractBase; + +%inline %{ +class PassedByValue { + int val; +public: + PassedByValue() { val = 0x12345678; } + int getVal() { return val; } +}; + +int doSomething(int x) { + int yy[256]; + yy[0] =0x9876; + return yy[0]; +} + +class DirectorPassByValueAbstractBase { +public: + virtual void virtualMethod(PassedByValue pbv) = 0; + virtual ~DirectorPassByValueAbstractBase () {} +}; + +class Caller { +public: + void call_virtualMethod(DirectorPassByValueAbstractBase &f) { + f.virtualMethod(PassedByValue()); + } +}; +%} diff --git a/Examples/test-suite/java/director_pass_by_value_runme.java b/Examples/test-suite/java/director_pass_by_value_runme.java new file mode 100644 index 000000000..24ded2ccf --- /dev/null +++ b/Examples/test-suite/java/director_pass_by_value_runme.java @@ -0,0 +1,48 @@ + +import director_pass_by_value.*; + +public class director_pass_by_value_runme { + + static { + try { + System.loadLibrary("director_pass_by_value"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + private static void WaitForGC() { + System.gc(); + System.runFinalization(); + try { + java.lang.Thread.sleep(10); + } catch (java.lang.InterruptedException e) { + } + } + + public static void main(String argv[]) { + Caller caller = new Caller(); + caller.call_virtualMethod(new director_pass_by_value_Derived()); + { + int countdown = 5; + while (true) { + WaitForGC(); + if (--countdown == 0) + break; + }; + } + // bug was the passByVal 'global' object was destroyed after the call to virtualMethod had finished. + int ret = director_pass_by_value_runme.passByVal.getVal(); + if (ret != 0x12345678) + throw new RuntimeException("Bad return value, got " + Integer.toHexString(ret)); + } + + static PassedByValue passByVal; +} + +class director_pass_by_value_Derived extends DirectorPassByValueAbstractBase { + public void virtualMethod(PassedByValue pbv) { + director_pass_by_value_runme.passByVal = pbv; + } +} diff --git a/Examples/test-suite/php/director_pass_by_value_runme.php b/Examples/test-suite/php/director_pass_by_value_runme.php new file mode 100644 index 000000000..8a8b84d67 --- /dev/null +++ b/Examples/test-suite/php/director_pass_by_value_runme.php @@ -0,0 +1,24 @@ +call_virtualMethod(new director_pass_by_value_Derived()); +$ret = $passByVal->getVal(); +if ($ret != 0x12345678) { + check::fail("Bad return value, got " . dechex($ret)); +} + +check::done(); +?> diff --git a/Examples/test-suite/python/director_pass_by_value_runme.py b/Examples/test-suite/python/director_pass_by_value_runme.py new file mode 100644 index 000000000..7744db962 --- /dev/null +++ b/Examples/test-suite/python/director_pass_by_value_runme.py @@ -0,0 +1,13 @@ +import director_pass_by_value + +passByVal = None +class director_pass_by_value_Derived(director_pass_by_value.DirectorPassByValueAbstractBase): + def virtualMethod(self, b): + global passByVal + passByVal = b + +# bug was the passByVal global object was destroyed after the call to virtualMethod had finished. +director_pass_by_value.Caller().call_virtualMethod(director_pass_by_value_Derived()) +ret = passByVal.getVal(); +if ret != 0x12345678: + raise RuntimeError("Bad return value, got " + hex(ret)) diff --git a/Lib/csharp/csharp.swg b/Lib/csharp/csharp.swg index f7b7927ba..d94336194 100644 --- a/Lib/csharp/csharp.swg +++ b/Lib/csharp/csharp.swg @@ -409,8 +409,8 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { #endif %typemap(directorin) SWIGTYPE -%{ $input = (void *)&$1; %} -%typemap(csdirectorin) SWIGTYPE "new $&csclassname($iminput, false)" +%{ $input = (void *)new $1_ltype((const $1_ltype &)$1); %} +%typemap(csdirectorin) SWIGTYPE "new $&csclassname($iminput, true)" %typemap(csdirectorout) SWIGTYPE "$&csclassname.getCPtr($cscall).Handle" /* Generic pointers and references */ diff --git a/Lib/csharp/swiginterface.i b/Lib/csharp/swiginterface.i index 3741b87ac..e5bfd23a4 100644 --- a/Lib/csharp/swiginterface.i +++ b/Lib/csharp/swiginterface.i @@ -31,7 +31,7 @@ $*csclassname ret = (cPtr == global::System.IntPtr.Zero) ? null : new $*csclassname(cPtr, $owner);$excode return ($*csinterfacename)ret; } -%typemap(csdirectorin) CTYPE "($&csinterfacename)new $&csclassname($iminput, false)" +%typemap(csdirectorin) CTYPE "($&csinterfacename)new $&csclassname($iminput, true)" %typemap(csdirectorin) CTYPE & "($csinterfacename)new $csclassname($iminput, false)" %typemap(csdirectorin) CTYPE *, CTYPE [] "($iminput == global::System.IntPtr.Zero) ? null : ($csinterfacename)new $csclassname($iminput, false)" %typemap(csdirectorin) CTYPE *const& "($iminput == global::System.IntPtr.Zero) ? null : ($*csinterfacename)new $*csclassname($iminput, false)" diff --git a/Lib/d/dswigtype.swg b/Lib/d/dswigtype.swg index 41336dc91..f91d6dfe6 100644 --- a/Lib/d/dswigtype.swg +++ b/Lib/d/dswigtype.swg @@ -57,7 +57,7 @@ #endif %typemap(directorin) SWIGTYPE - "$input = (void *)&$1;" + "$input = (void *)new $1_ltype((const $1_ltype &)$1);" %typemap(directorout) SWIGTYPE %{ if (!$input) { SWIG_DSetPendingException(SWIG_DIllegalArgumentException, "Unexpected null return for type $1_type"); @@ -65,7 +65,7 @@ } $result = *($&1_ltype)$input; %} -%typemap(ddirectorin) SWIGTYPE "new $&dclassname($winput, false)" +%typemap(ddirectorin) SWIGTYPE "new $&dclassname($winput, true)" %typemap(ddirectorout) SWIGTYPE "$&dclassname.swigGetCPtr($dcall)" %typemap(din) SWIGTYPE "$&dclassname.swigGetCPtr($dinput)" diff --git a/Lib/go/go.swg b/Lib/go/go.swg index bdd2aedea..53b653f7c 100644 --- a/Lib/go/go.swg +++ b/Lib/go/go.swg @@ -584,7 +584,7 @@ %typemap(goout) SWIGTYPE "" %typemap(directorin) SWIGTYPE -%{ $input = ($&1_ltype)&$1; %} +%{ $input = new $1_ltype((const $1_ltype &)$1); %} %typemap(godirectorin) SWIGTYPE "" diff --git a/Lib/java/java.swg b/Lib/java/java.swg index 96ca562b6..d763c5e6f 100644 --- a/Lib/java/java.swg +++ b/Lib/java/java.swg @@ -647,8 +647,8 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { %typemap(directorin,descriptor="L$packagepath/$&javaclassname;") SWIGTYPE %{ $input = 0; - *(($&1_ltype*)&$input) = &$1; %} -%typemap(javadirectorin) SWIGTYPE "new $&javaclassname($jniinput, false)" + *(($&1_ltype*)&$input) = new $1_ltype((const $1_ltype &)$1); %} +%typemap(javadirectorin) SWIGTYPE "new $&javaclassname($jniinput, true)" %typemap(javadirectorout) SWIGTYPE "$&javaclassname.getCPtr($javacall)" /* Generic pointers and references */ diff --git a/Lib/java/swiginterface.i b/Lib/java/swiginterface.i index 169118278..334464157 100644 --- a/Lib/java/swiginterface.i +++ b/Lib/java/swiginterface.i @@ -31,7 +31,7 @@ return (cPtr == 0) ? null : ($javainterfacename)new $javaclassname(cPtr, $owner); } -%typemap(javadirectorin) CTYPE "($&javainterfacename)new $&javaclassname($jniinput, false)" +%typemap(javadirectorin) CTYPE "($&javainterfacename)new $&javaclassname($jniinput, true)" %typemap(javadirectorin) CTYPE & "($javainterfacename)new $javaclassname($jniinput, false)" %typemap(javadirectorin) CTYPE *, CTYPE [] "($jniinput == 0) ? null : ($javainterfacename)new $javaclassname($jniinput, false)" %typemap(javadirectorin) CTYPE *const& "($jniinput == 0) ? null : ($*javainterfacename)new $*javaclassname($jniinput, false)" @@ -40,7 +40,7 @@ %typemap(javadirectorout) CTYPE *const& "$javacall.$*interfacename_GetInterfaceCPtr()" %typemap(directorin,descriptor="L$packagepath/$&javainterfacename;") CTYPE %{ $input = 0; - *(($&1_ltype*)&$input) = &$1; %} + *(($&1_ltype*)&$input) = new $1_ltype((const $1_ltype &)$1); %} %typemap(directorin,descriptor="L$packagepath/$javainterfacename;") CTYPE *, CTYPE [] %{ *(($&1_ltype)&$input) = ($1_ltype) $1; %} %typemap(directorin,descriptor="L$packagepath/$javainterfacename;") CTYPE & diff --git a/Lib/php/php.swg b/Lib/php/php.swg index 05d25a1df..45dfb0b0d 100644 --- a/Lib/php/php.swg +++ b/Lib/php/php.swg @@ -429,7 +429,7 @@ %typemap(directorin) SWIGTYPE { - SWIG_SetPointerZval($input, SWIG_as_voidptr(&$1), $&1_descriptor, 2); + SWIG_SetPointerZval($input, SWIG_as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&1_descriptor, 1|2); } %typemap(out) void ""; diff --git a/Lib/typemaps/swigtype.swg b/Lib/typemaps/swigtype.swg index 40d3ff5e9..d3633eb49 100644 --- a/Lib/typemaps/swigtype.swg +++ b/Lib/typemaps/swigtype.swg @@ -415,7 +415,7 @@ } %typemap(directorin,noblock=1) SWIGTYPE { - $input = SWIG_NewPointerObj(%as_voidptr(&$1), $&descriptor, %newpointer_flags); + $input = SWIG_NewPointerObj(%as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&descriptor, SWIG_POINTER_OWN | %newpointer_flags); } %typemap(directorin,noblock=1) SWIGTYPE & {