]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Emit postconditions before free'ing local variables
authorRico Tzschichholz <ricotz@ubuntu.com>
Thu, 12 Mar 2020 23:01:09 +0000 (00:01 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Fri, 13 Mar 2020 12:14:36 +0000 (13:14 +0100)
It was possible to cause segmentation-faults or use-after-free errors.

codegen/valaccodebasemodule.vala
tests/Makefile.am
tests/methods/postconditions.vala [new file with mode: 0644]

index 20f2507043d8456c977315b006df53a4491c8d96..0bf62de07ccb7840790350e3667567a8d38d9cae 100644 (file)
@@ -2339,6 +2339,14 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        pop_line ();
                }
 
+               if (b.parent_symbol is Method) {
+                       unowned Method m = (Method) b.parent_symbol;
+                       // check postconditions
+                       foreach (var postcondition in m.get_postconditions ()) {
+                               create_postcondition_statement (postcondition);
+                       }
+               }
+
                // free in reverse order
                for (int i = local_vars.size - 1; i >= 0; i--) {
                        var local = local_vars[i];
@@ -2363,10 +2371,6 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                        return_out_parameter (param);
                                }
                        }
-                       // check postconditions
-                       foreach (var postcondition in m.get_postconditions ()) {
-                               create_postcondition_statement (postcondition);
-                       }
                } else if (!unreachable_exit_block && b.parent_symbol is PropertyAccessor) {
                        var acc = (PropertyAccessor) b.parent_symbol;
                        if (acc.value_parameter != null && !acc.value_parameter.captured && requires_destroy (acc.value_parameter.variable_type)) {
@@ -3993,9 +3997,6 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        ccode.add_assignment (result_lhs, get_cvalue (stmt.return_expression));
                }
 
-               // free local variables
-               append_local_free (current_symbol);
-
                if (current_method != null) {
                        // check postconditions
                        foreach (Expression postcondition in current_method.get_postconditions ()) {
@@ -4003,6 +4004,9 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        }
                }
 
+               // free local variables
+               append_local_free (current_symbol);
+
                if (current_method != null && !current_method.coroutine) {
                        // assign values to output parameters if they are not NULL
                        // otherwise, free the value if necessary
index dcda2cbe05ae436b7674d252d37d0892428d95cc..9139b02d573e3f034b09a4c44b488a74f09a43b1 100644 (file)
@@ -120,6 +120,7 @@ TESTS = \
        methods/iterator.vala \
        methods/parameter-ref-array-resize.vala \
        methods/prepostconditions.vala \
+       methods/postconditions.vala \
        methods/same-name.vala \
        methods/symbolresolution.vala \
        methods/bug540483.vala \
diff --git a/tests/methods/postconditions.vala b/tests/methods/postconditions.vala
new file mode 100644 (file)
index 0000000..5cd9c59
--- /dev/null
@@ -0,0 +1,51 @@
+void foo (owned string[] a) ensures (a[1] == "bar") {
+}
+
+void foz (ref string[] a) ensures (a[1] == "bar") {
+       a = { "foo", "bar" };
+}
+
+void fom (out string[] a) ensures (a[1] == "bar") {
+       a = { "foo", "bar" };
+}
+
+string[] bar (owned string[] a) ensures (result[0] == "manam" && a[1] == "foo") {
+       return { "manam" };
+}
+
+string[] baz (ref string[] a) ensures (result[0] == "manam" && a[1] == "foo") {
+       a = { "bar", "foo" };
+       return { "manam" };
+}
+
+string[] bam (out string[] a) ensures (result[0] == "manam" && a[1] == "foo") {
+       a = { "bar", "foo" };
+       return { "manam" };
+}
+
+void main () {
+       {
+               foo ({ "foo", "bar" });
+       }
+       {
+               string[] a = {};
+               foz (ref a);
+               assert (a[0] == "foo");
+       }
+       {
+               string[] a;
+               fom (out a);
+               assert (a[0] == "foo");
+       }
+       {
+               assert (bar ({ "bar", "foo" })[0] == "manam");
+       }
+       {
+               string[] a = {};
+               assert (baz (ref a)[0] == "manam");
+       }
+       {
+               string[] a;
+               assert (bam (out a)[0] == "manam");
+       }
+}