diff mbox series

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

Message ID 20180312210614.GT8577@tucnak
State New
Headers show
Series Fix another CONSTRAINT_LEN related bug (PR middle-end/84831) | expand

Commit Message

Jakub Jelinek March 12, 2018, 9:06 p.m. UTC
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.


	Jakub

Comments

Richard Biener March 13, 2018, 8:09 a.m. UTC | #1
On Mon, 12 Mar 2018, Jakub Jelinek wrote:

> 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?

Ok.

Richard.

> 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
> 
>
diff mbox series

Patch

--- 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;
 }