[PATCH] Fix another CONSTRAINT_LEN related bug (PR middle-end/84831)

Jakub Jelinek jakub@redhat.com
Mon Mar 12 21:35:00 GMT 2018


Hi!

I thought the vregs pass is the first one to analyze constraints,
but I was wrong, already before that parse_{output,input}_constraint
are called, already during GIMPLE passes.  They don't really fail miserably
if , appears in the middle of multi-letter constraint (unlike e.g. the RA),
which is what my previous patch was fixing, but care if '\0' appears
in the middle of multi-letter constraint, because then we continue walking
random characters after the constraint string.  parse_input_constraint
is actually fine, because it has c_len = strlen (constraint); and uses
j < c_len, but parse_output_constraint doesn't do that.  While doing it
is possible, I think it is needlessly slow (needs to walk the constraint
twice), so this patch instead makes sure there are no '\0's in the middle
of constraints, if there are, doesn't jump over it.

The patch is larger because of reindentation, here is diff -upbd for
easier understanding what has changed.

--- gcc/stmt.c.jj	2018-01-03 10:19:55.150533956 +0100
+++ gcc/stmt.c	2018-03-12 13:25:03.790733765 +0100
@@ -247,7 +247,8 @@ parse_output_constraint (const char **co
     }
 
   /* Loop through the constraint string.  */
-  for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
+  for (p = constraint + 1; *p; )
+    {
     switch (*p)
       {
       case '+':
@@ -304,6 +305,11 @@ parse_output_constraint (const char **co
 	break;
       }
 
+      for (size_t len = CONSTRAINT_LEN (*p, p); len; len--, p++)
+	if (*p == '\0')
+	  break;
+    }
+
   return true;
 }
 
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-03-12  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/84831
	* stmt.c (parse_output_constraint): If the CONSTRAINT_LEN (*p, p)
	characters starting at p contain '\0' character, don't look beyond
	that.

--- gcc/stmt.c.jj	2018-01-03 10:19:55.150533956 +0100
+++ gcc/stmt.c	2018-03-12 13:25:03.790733765 +0100
@@ -247,62 +247,68 @@ parse_output_constraint (const char **co
     }
 
   /* Loop through the constraint string.  */
-  for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
-    switch (*p)
-      {
-      case '+':
-      case '=':
-	error ("operand constraint contains incorrectly positioned "
-	       "%<+%> or %<=%>");
-	return false;
-
-      case '%':
-	if (operand_num + 1 == ninputs + noutputs)
-	  {
-	    error ("%<%%%> constraint used with last operand");
-	    return false;
-	  }
-	break;
-
-      case '?':  case '!':  case '*':  case '&':  case '#':
-      case '$':  case '^':
-      case 'E':  case 'F':  case 'G':  case 'H':
-      case 's':  case 'i':  case 'n':
-      case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
-      case 'N':  case 'O':  case 'P':  case ',':
-	break;
-
-      case '0':  case '1':  case '2':  case '3':  case '4':
-      case '5':  case '6':  case '7':  case '8':  case '9':
-      case '[':
-	error ("matching constraint not valid in output operand");
-	return false;
-
-      case '<':  case '>':
-	/* ??? Before flow, auto inc/dec insns are not supposed to exist,
-	   excepting those that expand_call created.  So match memory
-	   and hope.  */
-	*allows_mem = true;
-	break;
-
-      case 'g':  case 'X':
-	*allows_reg = true;
-	*allows_mem = true;
-	break;
-
-      default:
-	if (!ISALPHA (*p))
-	  break;
-	enum constraint_num cn = lookup_constraint (p);
-	if (reg_class_for_constraint (cn) != NO_REGS
-	    || insn_extra_address_constraint (cn))
+  for (p = constraint + 1; *p; )
+    {
+      switch (*p)
+	{
+	case '+':
+	case '=':
+	  error ("operand constraint contains incorrectly positioned "
+		 "%<+%> or %<=%>");
+	  return false;
+
+	case '%':
+	  if (operand_num + 1 == ninputs + noutputs)
+	    {
+	      error ("%<%%%> constraint used with last operand");
+	      return false;
+	    }
+	  break;
+
+	case '?':  case '!':  case '*':  case '&':  case '#':
+	case '$':  case '^':
+	case 'E':  case 'F':  case 'G':  case 'H':
+	case 's':  case 'i':  case 'n':
+	case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
+	case 'N':  case 'O':  case 'P':  case ',':
+	  break;
+
+	case '0':  case '1':  case '2':  case '3':  case '4':
+	case '5':  case '6':  case '7':  case '8':  case '9':
+	case '[':
+	  error ("matching constraint not valid in output operand");
+	  return false;
+
+	case '<':  case '>':
+	  /* ??? Before flow, auto inc/dec insns are not supposed to exist,
+	     excepting those that expand_call created.  So match memory
+	     and hope.  */
+	  *allows_mem = true;
+	  break;
+
+	case 'g':  case 'X':
 	  *allows_reg = true;
-	else if (insn_extra_memory_constraint (cn))
 	  *allows_mem = true;
-	else
-	  insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
-	break;
-      }
+	  break;
+
+	default:
+	  if (!ISALPHA (*p))
+	    break;
+	  enum constraint_num cn = lookup_constraint (p);
+	  if (reg_class_for_constraint (cn) != NO_REGS
+	      || insn_extra_address_constraint (cn))
+	    *allows_reg = true;
+	  else if (insn_extra_memory_constraint (cn))
+	    *allows_mem = true;
+	  else
+	    insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
+	  break;
+	}
+
+      for (size_t len = CONSTRAINT_LEN (*p, p); len; len--, p++)
+	if (*p == '\0')
+	  break;
+    }
 
   return true;
 }

	Jakub



More information about the Gcc-patches mailing list