]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
bpf: remove huge memory waste with string allocation.
authorCupertino Miranda <cupertino.miranda@oracle.com>
Tue, 2 Apr 2024 11:04:28 +0000 (12:04 +0100)
committerCupertino Miranda <cupertino.miranda@oracle.com>
Fri, 19 Apr 2024 10:09:35 +0000 (11:09 +0100)
The BPF backend was allocating an unnecessarily large string when
constructing CO-RE relocations for enum types.
This patch also verifies that those enumerators are valid for CO-RE,
returning an error otherwise.

gcc/ChangeLog:
* config/bpf/core-builtins.cc (get_index_for_enum_value): Create
function.
(pack_enum_value): Check for enumerator and error out.
(process_enum_value): Correct string allocation.

gcc/config/bpf/core-builtins.cc

index e03e986e2c1b41b3ff543a1cf9d00ac66a04e14c..829acea98f792a75d52b912d23d25247014336d0 100644 (file)
@@ -795,6 +795,23 @@ process_field_expr (struct cr_builtins *data)
 static GTY(()) hash_map<tree, tree> *bpf_enum_mappings;
 tree enum_value_type = NULL_TREE;
 
+static int
+get_index_for_enum_value (tree type, tree expr)
+{
+  gcc_assert (TREE_CODE (expr) == CONST_DECL
+             && TREE_CODE (type) == ENUMERAL_TYPE);
+
+  unsigned int index = 0;
+  for (tree l = TYPE_VALUES (type); l; l = TREE_CHAIN (l))
+    {
+      gcc_assert (index < (1 << 16));
+      if (TREE_VALUE (l) == expr)
+       return index;
+      index++;
+    }
+  return -1;
+}
+
 /* Pack helper for the __builtin_preserve_enum_value.  */
 
 static struct cr_local
@@ -846,6 +863,16 @@ pack_enum_value_fail:
        ret.reloc_data.default_value = integer_one_node;
     }
 
+  if (ret.fail == false )
+    {
+      int index = get_index_for_enum_value (type, tmp);
+      if (index == -1 || index >= (1 << 16))
+       {
+         bpf_error ("enum value in CO-RE builtin cannot be represented");
+         ret.fail = true;
+       }
+    }
+
   ret.reloc_data.type = type;
   ret.reloc_data.kind = kind;
   return ret;
@@ -864,25 +891,17 @@ process_enum_value (struct cr_builtins *data)
 
   struct cr_final ret = { NULL, type, data->kind };
 
-  if (TREE_CODE (expr) == CONST_DECL
-     && TREE_CODE (type) == ENUMERAL_TYPE)
-    {
-      unsigned int index = 0;
-      for (tree l = TYPE_VALUES (type); l; l = TREE_CHAIN (l))
-       {
-         if (TREE_VALUE (l) == expr)
-           {
-             char *tmp = (char *) ggc_alloc_atomic ((index / 10) + 1);
-             sprintf (tmp, "%d", index);
-             ret.str = (const char *) tmp;
-
-             break;
-           }
-         index++;
-       }
-    }
-  else
-    gcc_unreachable ();
+  gcc_assert (TREE_CODE (expr) == CONST_DECL
+             && TREE_CODE (type) == ENUMERAL_TYPE);
+
+  int index = get_index_for_enum_value (type, expr);
+  gcc_assert (index != -1 && index < (1 << 16));
+
+  /* Index can only be a value up to 2^16.  Should always fit
+     in 6 chars.  */
+  char tmp[6];
+  sprintf (tmp, "%u", index);
+  ret.str = CONST_CAST (char *, ggc_strdup(tmp));
 
   return ret;
 }