diff mbox

69780 - [4.9/5/6 Regression] ICE on __builtin_alloca_with_align, with small alignment

Message ID 56C134ED.9060106@gmail.com
State New
Headers show

Commit Message

Martin Sebor Feb. 15, 2016, 2:16 a.m. UTC
The attached patch adds argument validation for
__builtin_alloca_with_align to reject arguments the middle end isn't
prepared to handle or that aren't meaningful for the API (constant
integers that aren't powers of 2 greater than or equal to 8).

Tested on x86_64-linux.

Martin

Comments

Jakub Jelinek Feb. 15, 2016, 8:29 a.m. UTC | #1
On Sun, Feb 14, 2016 at 07:16:13PM -0700, Martin Sebor wrote:
> +    case BUILT_IN_ALLOCA_WITH_ALIGN:
> +      {
> +	/* Get the requested alignment (in bits) if it's a constant
> +	   integer expression.  */
> +	HOST_WIDE_INT align =
> +	  TREE_CODE (args [1]) == INTEGER_CST ? tree_to_uhwi (args [1]) : 0;

Formatting.  = needs to be on the next line.

> +	/* Determine the exact power of 2 of the requested alignment.  */
> +	int alignpow = align ? tree_log2 (args [1]) : 0;
> +
> +	/* Reject invalid alignments.  */
> +	if (alignpow < 3 || MAX_STACK_ALIGNMENT < align)

This looks wrong.  Both the hardcoding of 3 (IMHO you should instead
do alignpow == -1 || align < BITS_PER_UNIT for the low boundary.
And MAX_STACK_ALIGNMENT certainly is not the upper bound of the alignment,
that is from what I understand the code something so that the alignment
in bits fits into unsigned int.  And perhaps if you aren't going to
use alignpow for anything, you can just check the low and high boundaries
and otherwise check (align & (align - 1)) == 0, or integer_pow2p (args [1]).

> +	  {
> +	    error_at (EXPR_LOC_OR_LOC (args [1], input_location),

No space before [.

> +		      "second argument to function %qE must be a constant "
> +		      "integer power of 2 between %qi and %qwu bits",
> +		      fndecl, CHAR_TYPE_SIZE,

And here, you are printing unrelated value to the one that you've checked.

> +		      (unsigned HOST_WIDE_INT)MAX_STACK_ALIGNMENT);
> +	    return false;
> +	  }
> +      return true;
> +      }
> +

	Jakub
diff mbox

Patch

PR middle-end/69780 - [4.9/5/6 Regression] ICE on __builtin_alloca_with_align
	with small alignment

gcc/testsuite/ChangeLog:
2016-02-14  Martin Sebor  <msebor@redhat.com>

	PR middle-end/69780
	* g++.dg/ext/builtin_alloca.C: New test.
	* gcc.dg/builtins-68.c: New test.

gcc/c-family/ChangeLog:
2016-02-14  Martin Sebor  <msebor@redhat.com>

	PR middle-end/69780
	* c-common.c (check_builtin_function_arguments): Validate and reject
	invalid arguments to __builtin_alloca_with_align.

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 233367)
+++ gcc/c-family/c-common.c	(working copy)
@@ -9818,6 +9818,29 @@  check_builtin_function_arguments (tree f
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
+    case BUILT_IN_ALLOCA_WITH_ALIGN:
+      {
+	/* Get the requested alignment (in bits) if it's a constant
+	   integer expression.  */
+	HOST_WIDE_INT align =
+	  TREE_CODE (args [1]) == INTEGER_CST ? tree_to_uhwi (args [1]) : 0;
+
+	/* Determine the exact power of 2 of the requested alignment.  */
+	int alignpow = align ? tree_log2 (args [1]) : 0;
+
+	/* Reject invalid alignments.  */
+	if (alignpow < 3 || MAX_STACK_ALIGNMENT < align)
+	  {
+	    error_at (EXPR_LOC_OR_LOC (args [1], input_location),
+		      "second argument to function %qE must be a constant "
+		      "integer power of 2 between %qi and %qwu bits",
+		      fndecl, CHAR_TYPE_SIZE,
+		      (unsigned HOST_WIDE_INT)MAX_STACK_ALIGNMENT);
+	    return false;
+	  }
+      return true;
+      }
+
     case BUILT_IN_CONSTANT_P:
       return builtin_function_validate_nargs (fndecl, nargs, 1);
 
Index: gcc/testsuite/g++.dg/ext/builtin_alloca.C
===================================================================
--- gcc/testsuite/g++.dg/ext/builtin_alloca.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/builtin_alloca.C	(working copy)
@@ -0,0 +1,183 @@ 
+// PR middle-end/69780 - [4.9/5/6 Regression] ICE on
+//     __builtin_alloca_with_align with small alignment
+// { dg-require-effective-target alloca }
+// { dg-do compile }
+
+#define CHAR_BIT  __CHAR_BIT__
+#define INT_MAX   __INT_MAX__
+#define INT_MIN   (-INT_MAX - 1)
+
+static void* p;
+
+// Verify that valid __builtin_alloca_with_align expressions are accepted.
+void test_valid (int n)
+{
+  enum {
+    A1   = CHAR_BIT *   1,
+    A2   = CHAR_BIT *   2,
+    A4   = CHAR_BIT *   4,
+    A8   = CHAR_BIT *   8,
+    A16  = CHAR_BIT *  16,
+    A32  = CHAR_BIT *  32
+  };
+
+  const int a1 = A1;
+  const int a2 = A2;
+  const int a4 = A4;
+  const int a8 = A8;
+  const int a16 = A16;
+  const int a32 = A32;
+
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  1);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  2);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  4);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  8);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 16);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 32);
+
+  p =  __builtin_alloca_with_align (n, A1);
+  p =  __builtin_alloca_with_align (n, A2);
+  p =  __builtin_alloca_with_align (n, A4);
+  p =  __builtin_alloca_with_align (n, A8);
+  p =  __builtin_alloca_with_align (n, A16);
+  p =  __builtin_alloca_with_align (n, A32);
+
+  p =  __builtin_alloca_with_align (n, a1);
+  p =  __builtin_alloca_with_align (n, a2);
+  p =  __builtin_alloca_with_align (n, a4);
+  p =  __builtin_alloca_with_align (n, a8);
+  p =  __builtin_alloca_with_align (n, a16);
+  p =  __builtin_alloca_with_align (n, a32);
+}
+
+template <int A> struct X { enum { Align = A }; };
+
+template <int A>
+void test_valid_template (int n)
+{
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, A);
+}
+
+template void test_valid_template<CHAR_BIT>(int);
+template void test_valid_template<CHAR_BIT * 2>(int);
+template void test_valid_template<CHAR_BIT * 4>(int);
+template void test_valid_template<CHAR_BIT * 8>(int);
+template void test_valid_template<CHAR_BIT * 16>(int);
+template void test_valid_template<CHAR_BIT * 32>(int);
+
+// Exercise the alignment in a dependent context.
+template <int A>
+void test_valid_template_dep (int n)
+{
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, X<A>::Align);
+}
+
+template void test_valid_template_dep<CHAR_BIT>(int);
+template void test_valid_template_dep<CHAR_BIT * 2>(int);
+template void test_valid_template_dep<CHAR_BIT * 4>(int);
+template void test_valid_template_dep<CHAR_BIT * 8>(int);
+template void test_valid_template_dep<CHAR_BIT * 16>(int);
+template void test_valid_template_dep<CHAR_BIT * 32>(int);
+
+// Invalid size must be rejected (and not cause an ICE).
+void test_arg1_non_int (int n)
+{
+  extern void f ();
+
+  p =  __builtin_alloca_with_align ((void*)0, 32);   // { dg-error "invalid conversion" }
+
+  p =  __builtin_alloca_with_align ("", 32);         // { dg-error "invalid conversion" }
+  p =  __builtin_alloca_with_align (L"", 32);        // { dg-error "invalid conversion" }
+  p =  __builtin_alloca_with_align (f, 32);          // { dg-error "invalid conversion" }
+}
+
+// Non-integer alignment must be rejected.
+void test_arg2_non_int (int n)
+{
+  // Verify the full text of the diagnostic just once.
+  p =  __builtin_alloca_with_align (n, 0.0);         // { dg-error "second argument to function .__builtin_alloca_with_align. must be a constant integer power of 2 between .8. and " }
+
+  p =  __builtin_alloca_with_align (n, (void*)0);    // { dg-error "invalid conversion|must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, "");          // { dg-error "invalid conversion|must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, L"");         // { dg-error "invalid conversion|must be a constant integer" }
+}
+
+// Integer alignment that's not a constant expression must be rejected.
+void test_arg2_non_const (int n, int a1)
+{
+  extern const int a2;
+  static volatile const int a3 = CHAR_BIT;
+  
+  p =  __builtin_alloca_with_align (n, a1);       // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, a2);       // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, a3);       // { dg-error "must be a constant integer" }
+}
+
+// Constant integer alignment that's not a power of 2 positive multiple
+// of CHAR_BIT must be rejected.
+void test_arg2_non_pow2 (int n)
+{
+  p =  __builtin_alloca_with_align (n, INT_MIN);     // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, -1);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, !1);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, !0);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  0);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  1);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  2);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  3);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  4);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  5);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  6);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  7);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  9);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 10);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 11);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 12);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 13);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 14);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 15);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 17);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 31);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 33);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 63);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 65);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, INT_MAX);     // { dg-error "must be a constant integer" }
+}
+
+// Exercise invalid alignment specified by a template argument.
+template <int A>
+void test_invalid_template_1 (int n)
+{
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, A);           // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_1<1>(int);
+
+template <int A>
+void test_invalid_template_7 (int n)
+{
+  p =  __builtin_alloca_with_align (n, A);           // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_7<7>(int);
+
+template <int A>
+void test_invalid_template_9 (int n)
+{
+  p =  __builtin_alloca_with_align (n, A);           // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_9<9>(int);
+
+// Exercise invalid alignment specified by a template dependent argument.
+template <int A>
+void test_invalid_template_dep_1 (int n)
+{
+  p =  __builtin_alloca_with_align (n, X<A>::Align);     // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_dep_1<1>(int);
Index: gcc/testsuite/gcc.dg/builtins-68.c
===================================================================
--- gcc/testsuite/gcc.dg/builtins-68.c	(revision 0)
+++ gcc/testsuite/gcc.dg/builtins-68.c	(working copy)
@@ -0,0 +1,101 @@ 
+/* PR middle-end/69780 - [4.9/5/6 Regression] ICE on
+     __builtin_alloca_with_align with small alignment */
+/* { dg-require-effective-target alloca } */
+/* { dg-do compile } */
+
+#define CHAR_BIT  __CHAR_BIT__
+#define INT_MAX   __INT_MAX__
+#define INT_MIN   (-INT_MAX - 1)
+
+static void* p;
+
+/* Verify that valid __builtin_alloca_with_align expressions are accepted.  */
+void test_valid (int n)
+{
+  enum {
+    A1   = CHAR_BIT *   1,
+    A2   = CHAR_BIT *   2,
+    A4   = CHAR_BIT *   4,
+    A8   = CHAR_BIT *   8,
+    A16  = CHAR_BIT *  16,
+    A32  = CHAR_BIT *  32
+  };
+
+  /* Valid alignments are power of 2 positive multiples of CHAR_BIT.  */
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  1);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  2);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  4);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  8);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 16);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 32);
+
+  p =  __builtin_alloca_with_align (n, A1);
+  p =  __builtin_alloca_with_align (n, A2);
+  p =  __builtin_alloca_with_align (n, A4);
+  p =  __builtin_alloca_with_align (n, A8);
+  p =  __builtin_alloca_with_align (n, A16);
+  p =  __builtin_alloca_with_align (n, A32);
+}
+
+/* Non-integer alignments must be rejected.  */
+void test_arg2_non_int (int n)
+{
+  /* Verify the full text of the diagnostic just once.  */
+  p =  __builtin_alloca_with_align (n, 0.0);         /* { dg-error "second argument to function .__builtin_alloca_with_align. must be a constant integer power of 2 between .8. and " } */
+
+  /* Disable diagnostic complaining about converting void* to int that
+     preempts the "constant integer expression" error.  */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wint-conversion"
+
+  p =  __builtin_alloca_with_align (n, (void*)0);    /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, "");          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, L"");         /* { dg-error "must be a constant integer" } */
+
+#pragma GCC diagnostic pop
+
+}
+
+/* Integer alignment that's not a constant expression must be rejected.  */
+void test_arg2_non_const (int n, int a1)
+{
+  extern const int a2;
+  static const int a3 = CHAR_BIT;
+  static volatile const int a4 = CHAR_BIT;
+  
+  p =  __builtin_alloca_with_align (n, a1);       /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, a2);       /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, a3);       /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, a4);       /* { dg-error "must be a constant integer" } */
+}
+
+/* Constant integer alignment that's not a power of 2 positive multiple
+   of CHAR_BIT must be rejected.  */
+void test_arg2_non_pow2 (int n)
+{
+  p =  __builtin_alloca_with_align (n, INT_MIN);     /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, -1);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, !1);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, !0);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  0);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  1);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  2);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  3);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  4);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  5);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  6);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  7);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  9);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 10);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 11);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 12);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 13);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 14);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 15);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 17);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 31);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 33);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 63);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 65);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, INT_MAX);     /* { dg-error "must be a constant integer" } */
+}