]> 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>
Fri, 1 Jan 2021 10:10:41 +0000 (11:10 +0100)
codegen/valaccodebasemodule.vala
tests/Makefile.am
tests/objects/property-notify-owned-getter.vala [new file with mode: 0644]

index b7db3183514dae06b4fdafd608c2398b1535b4f0..d6463a8aa4590b0f08a41e2376b68f762a4e33dc 100644 (file)
@@ -1948,10 +1948,14 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                        get_call.add_argument (new CCodeIdentifier (is_virtual ? "base" : "self"));
 
                                        if (property_type is ArrayType && get_ccode_array_length (prop)) {
+                                               ccode.add_declaration (get_ccode_name (property_type), new CCodeVariableDeclarator ("old_value"));
                                                ccode.add_declaration (get_ccode_array_length_type (prop), 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);
                                                CCodeFunctionCall ccall;
                                                if (context.profile == Profile.POSIX) {
                                                        ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_cmp_wrapper (new CCodeIdentifier ("strcmp"))));
@@ -1959,7 +1963,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                                        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"));
@@ -1979,12 +1983,22 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                                }
                                                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 3d41840ed264c02e8b1ead92615c6eca387a0566..8e5935cffa06ed152f37b4a27adaa0558a882f61 100644 (file)
@@ -453,6 +453,7 @@ TESTS = \
        objects/property-base-access.vala \
        objects/property-enum.vala \
        objects/property-notify.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");
+}