On November 18, 2016 10:41:06 PM GMT+01:00, Jakub Jelinek <ja...@redhat.com> 
wrote:
>Hi!
>
>The following testcase ICEs because of buffer overflow in the
>expand_target_clones function.  The main bug is that get_attr_str
>doesn't count the commas in the strings, so while it handles
>__attribute__((target_clones ("avx", "foo", "avx2", "avx512f",
>"default")))
>it doesn't handle
>__attribute__((target_clones ("avx,foo,avx2,avx512f,default")))
>which is also meant to be valid.
>This is fixed by the get_attr_str hunk.
>The rest of the changes are to avoid leaking memory, avoid double
>diagnostics (if targetm.target_option.valid_attribute_p fails,
>it has reported errors already, so there is no point to report
>further error or warning), fixing location_t of the diagnostics
>(targetm.target_option.valid_attribute_p uses input_location),
>and various formatting fixes and cleanups.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Richard.

>2016-11-18  Jakub Jelinek  <ja...@redhat.com>
>
>       PR middle-end/78419
>       * multiple_target.c (get_attr_len): Start with argnum and increment
>       argnum on every arg.  Use strchr in a loop instead of counting commas
>       manually.
>       (get_attr_str): Increment argnum for every comma in the string.
>       (separate_attrs): Use for instead of while loop, simplify.
>       (expand_target_clones): Rename defenition argument to definition.
>       Free attrs and attr_str even when diagnosing errors.  Temporarily
>       change input_location around targetm.target_option.valid_attribute_p
>       calls.  Don't emit warning or errors if that function fails.
>
>       * gcc.target/i386/pr78419.c: New test.
>
>--- gcc/multiple_target.c.jj   2016-08-29 12:17:37.000000000 +0200
>+++ gcc/multiple_target.c      2016-11-18 14:14:11.684489030 +0100
>@@ -101,22 +101,18 @@ get_attr_len (tree arglist)
> {
>   tree arg;
>   int str_len_sum = 0;
>-  int argnum = 1;
>+  int argnum = 0;
> 
>   for (arg = arglist; arg; arg = TREE_CHAIN (arg))
>     {
>-      unsigned int i;
>       const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
>-      int len = strlen (str);
>-
>+      size_t len = strlen (str);
>       str_len_sum += len + 1;
>-      if (arg != arglist)
>+      for (const char *p = strchr (str, ','); p; p = strchr (p + 1,
>','))
>       argnum++;
>-      for (i = 0; i < strlen (str); i++)
>-      if (str[i] == ',')
>-        argnum++;
>+      argnum++;
>     }
>-  if (argnum == 1)
>+  if (argnum <= 1)
>     return -1;
>   return str_len_sum;
> }
>@@ -134,8 +130,9 @@ get_attr_str (tree arglist, char *attr_s
>   for (arg = arglist; arg; arg = TREE_CHAIN (arg))
>     {
>       const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
>-
>       size_t len = strlen (str);
>+      for (const char *p = strchr (str, ','); p; p = strchr (p + 1,
>','))
>+      argnum++;
>       memcpy (attr_str + str_len_sum, str, len);
>       attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0';
>       str_len_sum += len + 1;
>@@ -152,19 +149,16 @@ separate_attrs (char *attr_str, char **a
> {
>   int i = 0;
>   bool has_default = false;
>-  char *attr = strtok (attr_str, ",");
> 
>-  while (attr != NULL)
>+  for (char *attr = strtok (attr_str, ",");
>+       attr != NULL; attr = strtok (NULL, ","))
>     {
>       if (strcmp (attr, "default") == 0)
>       {
>         has_default = true;
>-        attr = strtok (NULL, ",");
>         continue;
>       }
>-      attrs[i] = attr;
>-      attr = strtok (NULL, ",");
>-      i++;
>+      attrs[i++] = attr;
>     }
>   if (!has_default)
>     return -1;
>@@ -235,7 +229,7 @@ create_target_clone (cgraph_node *node,
>    create the appropriate clone for each valid target attribute.  */
> 
> static bool
>-expand_target_clones (struct cgraph_node *node, bool defenition)
>+expand_target_clones (struct cgraph_node *node, bool definition)
> {
>   int i;
>   /* Parsing target attributes separated by comma.  */
>@@ -266,6 +260,8 @@ expand_target_clones (struct cgraph_node
>     {
>       error_at (DECL_SOURCE_LOCATION (node->decl),
>               "default target was not set");
>+      XDELETEVEC (attrs);
>+      XDELETEVEC (attr_str);
>       return false;
>     }
> 
>@@ -286,22 +282,24 @@ expand_target_clones (struct cgraph_node
> 
>       create_new_asm_name (attr, suffix);
>       /* Create new target clone.  */
>-      cgraph_node *new_node = create_target_clone (node, defenition,
>suffix);
>+      cgraph_node *new_node = create_target_clone (node, definition,
>suffix);
>       XDELETEVEC (suffix);
> 
>       /* Set new attribute for the clone.  */
>       tree attributes = make_attribute ("target", attr,
>                                       DECL_ATTRIBUTES (new_node->decl));
>       DECL_ATTRIBUTES (new_node->decl) = attributes;
>+      location_t saved_loc = input_location;
>+      input_location = DECL_SOURCE_LOCATION (node->decl);
>    if (!targetm.target_option.valid_attribute_p (new_node->decl, NULL,
>-                                                  TREE_VALUE (attributes), 0))
>+                                                  TREE_VALUE (attributes),
>+                                                  0))
>       {
>-        warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
>-                    "attribute(target_clones(\"%s\")) is not "
>-                    "valid for current target", attr);
>+        input_location = saved_loc;
>         continue;
>       }
> 
>+      input_location = saved_loc;
>       decl2_v = new_node->function_version ();
>       if (decl2_v != NULL)
>         continue;
>@@ -320,22 +318,20 @@ expand_target_clones (struct cgraph_node
>       DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
>     }
> 
>-  /* Setting new attribute to initial function.  */
>-  tree attributes =  make_attribute ("target", "default",
>-                                   DECL_ATTRIBUTES (node->decl));
>-  DECL_ATTRIBUTES (node->decl) = attributes;
>-  if (!targetm.target_option.valid_attribute_p (node->decl, NULL,
>-                                              TREE_VALUE (attributes), 0))
>-    {
>-      error_at (DECL_SOURCE_LOCATION (node->decl),
>-              "attribute(target_clones(\"default\")) is not "
>-              "valid for current target");
>-      return false;
>-    }
>-
>   XDELETEVEC (attrs);
>   XDELETEVEC (attr_str);
>-  return true;
>+
>+  /* Setting new attribute to initial function.  */
>+  tree attributes = make_attribute ("target", "default",
>+                                  DECL_ATTRIBUTES (node->decl));
>+  DECL_ATTRIBUTES (node->decl) = attributes;
>+  location_t saved_loc = input_location;
>+  input_location = DECL_SOURCE_LOCATION (node->decl);
>+  bool ret
>+    = targetm.target_option.valid_attribute_p (node->decl, NULL,
>+                                             TREE_VALUE (attributes), 0);
>+  input_location = saved_loc;
>+  return ret;
> }
> 
> static bool target_clone_pass;
>--- gcc/testsuite/gcc.target/i386/pr78419.c.jj 2016-11-18
>14:17:32.500967895 +0100
>+++ gcc/testsuite/gcc.target/i386/pr78419.c    2016-11-18
>14:17:09.000000000 +0100
>@@ -0,0 +1,23 @@
>+/* PR middle-end/78419 */
>+/* { dg-do compile } */
>+
>+static double bar (double *__restrict, double *__restrict, int)
>+__attribute__ ((target_clones("avx,foo,avx2,avx512f,default")));
>+
>+double
>+foo (double *__restrict a, double *__restrict b, int n)
>+{
>+  return bar (a,b,n);
>+}
>+
>+double
>+bar (double *__restrict a, double *__restrict b, int n)       /* { dg-error
>"attribute\[^\n\r]*foo\[^\n\r]* is unknown" } */
>+{
>+  double s;
>+  int i;
>+  s = 0.0;
>+  for (i=0; i<n; i++)
>+    s += a[i] + b[i];
>+
>+  return s;
>+}
>
>       Jakub


Reply via email to