[vala/0.40] codegen: Use temp-vars for ellipsis out-arguments to fix memory management



commit a403639bab6c9523ea40ed546064bac5f3189e0c
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Sun Dec 23 23:08:31 2018 +0100

    codegen: Use temp-vars for ellipsis out-arguments to fix memory management
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/722

 codegen/valaccodemethodcallmodule.vala | 32 ++++++++++++++++---------
 tests/Makefile.am                      |  1 +
 tests/methods/varargs-out.vala         | 43 ++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 11 deletions(-)
---
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 81464868f..2b3f5ca68 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -348,10 +348,13 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 
                        var carg_map = in_arg_map;
 
+                       Parameter? param = null;
                        if (params_it.next ()) {
-                               var param = params_it.get ();
+                               param = params_it.get ();
                                ellipsis = param.params_array || param.ellipsis;
-                               if (!ellipsis) {
+                       }
+
+                       if (param != null && !ellipsis) {
                                        if (param.direction == ParameterDirection.OUT) {
                                                carg_map = out_arg_map;
                                        }
@@ -456,16 +459,27 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                                        if (get_ccode_type (param) != null) {
                                                cexpr = new CCodeCastExpression (cexpr, get_ccode_type 
(param));
                                        }
+                       } else {
+                               // ellipsis arguments
+                               var unary = arg as UnaryExpression;
+                               if (ellipsis && unary != null && unary.operator == UnaryOperator.OUT) {
+                                       carg_map = out_arg_map;
+
+                                       arg.target_value = null;
+
+                                       // infer type and ownership from argument expression
+                                       var temp_var = get_temp_variable (arg.value_type, 
arg.value_type.value_owned, null, true);
+                                       emit_temp_var (temp_var);
+                                       set_cvalue (arg, get_variable_cexpression (temp_var.name));
+                                       arg.target_value.value_type = arg.value_type;
+
+                                       cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
get_cvalue (arg));
                                } else {
                                        cexpr = handle_struct_argument (null, arg, cexpr);
                                }
-                               arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
-                       } else {
-                               // default argument position
-                               cexpr = handle_struct_argument (null, arg, cexpr);
-                               arg_pos = get_param_pos (i, ellipsis);
                        }
 
+                       arg_pos = get_param_pos (param != null ? get_ccode_pos (param) : i, ellipsis);
                        carg_map.set (arg_pos, cexpr);
 
                        if (arg is NamedArgument && ellipsis) {
@@ -845,10 +859,6 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                        
                        if (params_it.next ()) {
                                param = params_it.get ();
-                               if (param.params_array || param.ellipsis) {
-                                       // ignore ellipsis arguments as we currently don't use temporary 
variables for them
-                                       break;
-                               }
                        }
 
                        var unary = arg as UnaryExpression;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8cda19baf..4c6e08613 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -125,6 +125,7 @@ TESTS = \
        methods/printf-invalid.test \
        methods/printf-constructor.vala \
        methods/printf-constructor-invalid.test \
+       methods/varargs-out.vala \
        control-flow/assigned-local-variable.vala \
        control-flow/break.vala \
        control-flow/break-invalid.test \
diff --git a/tests/methods/varargs-out.vala b/tests/methods/varargs-out.vala
new file mode 100644
index 000000000..88b0fb999
--- /dev/null
+++ b/tests/methods/varargs-out.vala
@@ -0,0 +1,43 @@
+class Foo : Object {
+       public string? name { get; set; }
+       public int id { get; set; }
+}
+
+bool get_foo_varg (string s, ...) {
+       var args = va_list ();
+       Foo** out_foo = args.arg ();
+       *out_foo = foo_static.ref ();
+       return true;
+}
+
+Foo foo_static;
+
+void main () {
+       {
+               foo_static = new Foo ();
+       }
+       assert (foo_static.ref_count == 1);
+
+       {
+               Foo foo;
+
+               get_foo_varg ("foo", out foo);
+               assert (foo.ref_count == 2);
+
+               if (get_foo_varg ("foo", out foo)) {
+                       assert (foo.ref_count == 2);
+               }
+               assert (foo.ref_count == 2);
+       }
+       assert (foo_static.ref_count == 1);
+
+       {
+               foo_static.@set ("name", "foo", "id", 42);
+
+               string? name;
+               int id;
+               foo_static.@get ("name", out name, "id", out id);
+               assert (name == "foo");
+               assert (id == 42);
+       }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]