]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Use memset to initialize inline-allocated array with non-constant size b95a766454eb914f4eb5a68e9040e03faffabf52
authorRico Tzschichholz <ricotz@ubuntu.com>
Wed, 18 Mar 2020 13:05:13 +0000 (14:05 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Wed, 18 Mar 2020 13:05:13 +0000 (14:05 +0100)
In addition to a0bb129e5a2e8580eb272d9a68ba054e7b170dba

Fixes https://gitlab.gnome.org/GNOME/vala/issues/910

codegen/valaccodebasemodule.vala
tests/arrays/fixed-length-init0-not-allowed.vala

index 27b0ba10154fe300115c42452219b2d1a849e171..a21b8f3155431d941953cbfbe5a27262163a6321 100644 (file)
@@ -1453,6 +1453,19 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
        }
 
+       public static bool is_constant_ccode (CodeNode expr) {
+               if (expr is Constant) {
+                       // Local constants are not considered constant in C
+                       return !(((Constant) expr).parent_symbol is Block);
+               } else if (expr is MemberAccess) {
+                       return is_constant_ccode (((MemberAccess) expr).symbol_reference);
+               } else if (expr is CastExpression) {
+                       return is_constant_ccode (((CastExpression) expr).inner);
+               }
+
+               return false;
+       }
+
        /**
         * Returns whether the passed cexpr is a pure expression, i.e. an
         * expression without side-effects.
@@ -2523,9 +2536,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
                                // try to initialize uninitialized variables
                                // initialization not necessary for variables stored in closure
-                               if (is_init_allowed (local.variable_type)) {
+                               CCodeExpression? size = null;
+                               if (!requires_memset_init (local, out size)) {
                                        cvar.initializer = default_value_for_type (local.variable_type, true);
                                        cvar.init0 = true;
+                               } else if (size != null && local.initializer == null) {
+                                       cfile.add_include ("string.h");
+                                       var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+                                       memset_call.add_argument (get_variable_cexpression (local.name));
+                                       memset_call.add_argument (new CCodeConstant ("0"));
+                                       memset_call.add_argument (size);
+                                       ccode.add_expression (memset_call);
                                }
 
                                ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
@@ -3786,9 +3807,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        }
                } else {
                        var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix (local.variable_type));
-                       if (init && is_init_allowed (local.variable_type)) {
+                       CCodeExpression? size = null;
+                       if (init && !requires_memset_init (local, out size)) {
                                cvar.initializer = default_value_for_type (local.variable_type, true, on_error);
                                cvar.init0 = true;
+                       } else if (init && size != null && local.initializer == null) {
+                               cfile.add_include ("string.h");
+                               var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+                               memset_call.add_argument (get_variable_cexpression (local.name));
+                               memset_call.add_argument (new CCodeConstant ("0"));
+                               memset_call.add_argument (size);
+                               ccode.add_expression (memset_call);
                        }
                        ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
                }
@@ -6249,15 +6278,16 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return true;
        }
 
-       public bool is_init_allowed (DataType type) {
-               unowned ArrayType? array_type = type as ArrayType;
-               if (array_type != null && array_type.inline_allocated
-                  && array_type.fixed_length) {
-                  unowned Constant? c = array_type.length.symbol_reference as Constant;
-                  // our local constants are not actual constants in C
-                  return (c == null || !(c.parent_symbol is Block));
+       public bool requires_memset_init (Variable variable, out CCodeExpression? size) {
+               unowned ArrayType? array_type = variable.variable_type as ArrayType;
+               if (array_type != null && array_type.fixed_length && !is_constant_ccode (array_type.length)) {
+                       var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+                       sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
+                       size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
+                       return true;
                }
-               return true;
+               size = null;
+               return false;
        }
 
        public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
index 932f011b34cfec0629715e670a07d4ffe81ee9a8..9cb8a43a70e3069ee1dc789c5e9b308b768e6136 100644 (file)
@@ -1,13 +1,49 @@
+const int BAR = 1024;
+
 void main () {
-       const int FOO = 4;
+       {
+               const int FOO = 4;
+
+               char bar[FOO] = { 'f', 'o', 'o', '\0' };
+               assert ((string) bar == "foo");
+
+               char baz[FOO];
+               baz[0] = 'f';
+               baz[1] = 'o';
+               baz[2] = 'o';
+               baz[3] = '\0';
+               assert ((string) baz == "foo");
+       }
+       {
+               const int FOO = 1024;
+
+               string foo[FOO];
+
+               assert (foo[0] == null);
+               assert (foo[FOO / 2] == null);
+               assert (foo[FOO - 1] == null);
+       }
+       {
+               const int FOO = 1024;
+
+               string array[16 * FOO];
+
+               assert (array[0] == null);
+               assert (array[16 * FOO / 2] == null);
+               assert (array[16 * FOO - 1] == null);
+       }
+       {
+               string array[BAR];
 
-       char bar[FOO] = { 'f', 'o', 'o', '\0' };
-       assert ((string) bar == "foo");
+               assert (array[0] == null);
+               assert (array[BAR / 2] == null);
+               assert (array[BAR - 1] == null);
+       }
+       {
+               string array[16 * BAR];
 
-       char baz[FOO];
-       baz[0] = 'f';
-       baz[1] = 'o';
-       baz[2] = 'o';
-       baz[3] = '\0';
-       assert ((string) baz == "foo");
+               assert (array[0] == null);
+               assert (array[16 * BAR / 2] == null);
+               assert (array[16 * BAR - 1] == null);
+       }
 }