]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Don't leak memory on internal value comparison of property setter
authorRico Tzschichholz <ricotz@ubuntu.com>
Fri, 1 Jan 2021 10:10:41 +0000 (11:10 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Sun, 3 Jan 2021 12:34:35 +0000 (13:34 +0100)
codegen/valaccodebasemodule.vala
tests/Makefile.am
tests/objects/property-notify-owned-getter.vala [new file with mode: 0644]

index 93236afe1e94c875c2e00092e90b4e410ac203ff..5974c577a6ce28d872637c6f43367da3352e60b8 100644 (file)
@@ -1879,13 +1879,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                        get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
 
                                        if (property_type is ArrayType) {
+                                               ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
                                                ccode.add_declaration ("int", new CCodeVariableDeclarator ("old_value_length"));
                                                get_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("old_value_length")));
-                                               ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value")));
+                                               ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
+                                               ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
                                        } else if (property_type.compatible (string_type)) {
+                                               ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
+                                               ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
                                                var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
                                                ccall.add_argument (new CCodeIdentifier ("value"));
-                                               ccall.add_argument (get_call);
+                                               ccall.add_argument (new CCodeIdentifier ("old_value"));
                                                ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("0")));
                                        } else if (property_type is StructValueType) {
                                                ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
@@ -1901,12 +1905,22 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                                ccall.add_argument (get_expr);
                                                ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, ccall, new CCodeConstant ("TRUE")));
                                        } else {
-                                               ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_call, new CCodeIdentifier ("value")));
+                                               ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
+                                               ccode.add_assignment (new CCodeIdentifier ("old_value"), get_call);
+                                               ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("old_value"), new CCodeIdentifier ("value")));
                                        }
 
                                        acc.body.emit (this);
                                        ccode.add_expression (notify_call);
                                        ccode.close ();
+
+                                       if (prop.get_accessor.value_type.is_disposable ()) {
+                                               var old_value = new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("old_value"), true);
+                                               if (property_type is ArrayType && get_ccode_array_length (prop)) {
+                                                       old_value.append_array_length_cvalue (new CCodeIdentifier ("old_value_length"));
+                                               }
+                                               ccode.add_expression (destroy_value (old_value));
+                                       }
                                } else {
                                        acc.body.emit (this);
                                        ccode.add_expression (notify_call);
index 5c84e74d462249a14efaad9fdefe771c567bab7a..d6b1bfea5182c22cd0667947dadc960b7057056d 100644 (file)
@@ -374,6 +374,7 @@ TESTS = \
        objects/property-array-length.vala \
        objects/property-base-access.vala \
        objects/property-enum.vala \
+       objects/property-notify-owned-getter.vala \
        objects/property-ownership.vala \
        objects/property-read-only-auto.vala \
        objects/property-read-only-write.test \
diff --git a/tests/objects/property-notify-owned-getter.vala b/tests/objects/property-notify-owned-getter.vala
new file mode 100644 (file)
index 0000000..7633aba
--- /dev/null
@@ -0,0 +1,54 @@
+class Bar : Object {
+}
+
+struct Manam {
+       public string s;
+}
+
+class Foo : Object {
+       public Bar o { owned get; set; }
+
+       public Manam st { owned get; set; }
+
+       public Manam? stn { owned get; set; }
+
+       public string s { owned get; set; }
+
+       public string[] strv { owned get; set; }
+
+       construct {
+               o = bar;
+               st = { "foo" };
+               stn = { "bar" };
+               s = "foo";
+               strv = { "foo", "bar" };
+       }
+}
+
+Bar bar;
+
+void main () {
+       bar = new Bar ();
+       assert (bar.ref_count == 1);
+
+       var foo = new Foo ();
+       assert (bar.ref_count == 2);
+       foo.o = bar;
+       assert (bar.ref_count == 2);
+
+       assert (foo.st.s == "foo");
+       foo.st = { "manam" };
+       assert (foo.st.s == "manam");
+
+       assert (foo.stn.s == "bar");
+       foo.stn = { "minim" };
+       assert (foo.stn.s == "minim");
+
+       assert (foo.s == "foo");
+       foo.s = "manam";
+       assert (foo.s == "manam");
+
+       assert (foo.strv[1] == "bar");
+       foo.strv = { "manam", "minim" };
+       assert (foo.strv[1] == "minim");
+}