This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] c/66516 - missing diagnostic on taking the address of a builtin function


Attached is a patch to reject C and C++ constructs that result
in obtaining a pointer (or a reference in C++) to a builtin
function.  These constructs are currently silently accepted by
GCC and, in most cases(*), result in a linker error.  The patch
brings GCC on par with Clang by rejecting all such constructs.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Okay to commit to trunk?

Martin

[*] Besides rejecting constructs that lead to linker errors
the patch leads to rejecting also some benign constructs (that
are also rejected by Clang).  For example, the program below
currently compiles and links successfully with GCC 5.1 is
rejected with the patch applied.  That's intended (but I'm
open to arguments against it).

$ cat /build/tmp/u.cpp && /build/gcc-66516/gcc/xg++ -B/build/gcc-66516/gcc -Wall -c -std=c++11 /build/tmp/u.cpp
static constexpr int (&r)(int) = __builtin_ffs;

int main () { return r (0); }
/build/tmp/u.cpp:1:34: error: invalid initialization of a reference with a builtin function
 static constexpr int (&r)(int) = __builtin_ffs;
                                  ^
2015-06-21  Martin Sebor  <msebor@redhat.com>

	PR c/66516
	* c/c-typeck.c (default_function_array_conversion): Reject
	converting a builtin function to a pointer.
	(parser_build_unary_op): Reject taking the address of a builtin
	function.
	* cp/call.c (convert_like_real): Reject converting a builtin function
	to a pointer.
	(initialize_reference): Reject initializing a reference with a builtin
	function.
	* cp/typeck.c (cp_build_addr_expr_strict): Reject taking the address
	of a builtin function.
	(build_reinterpret_cast_1): Reject casting a builtin function to
	a pointer.
	(convert_for_initialization): Reject initializing a pointer with
	the a builtin function.

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 636e0bb..637a292 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cilk.h"
 #include "gomp-constants.h"

+#include <stdlib.h>
+
 /* Possible cases of implicit bad conversions.  Used to select
    diagnostic messages in convert_for_assignment.  */
 enum impl_conv {
@@ -1940,6 +1942,12 @@ default_function_array_conversion (location_t loc, struct c_expr exp)
       }
       break;
     case FUNCTION_TYPE:
+      if (DECL_IS_BUILTIN (exp.value))
+	{
+	  error_at (loc, "converting builtin function to a pointer");
+	  exp.value = error_mark_node;
+	}
+      else
 	exp.value = function_to_pointer_conversion (loc, exp.value);
       break;
     default:
@@ -3384,7 +3392,14 @@ parser_build_unary_op (location_t loc, enum tree_code code, struct c_expr arg)
   result.original_code = code;
   result.original_type = NULL;

-  if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
+  if (code == ADDR_EXPR
+      && TREE_CODE (TREE_TYPE (arg.value)) == FUNCTION_TYPE
+      && DECL_IS_BUILTIN (arg.value))
+    {
+      error_at (loc, "taking address of a builtin function");
+      result.value = error_mark_node;
+    }
+  else if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
     overflow_warning (loc, result.value);

   return result;
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 2d90ed9..df4cc77 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6570,6 +6570,13 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	    expr = build_target_expr_with_type (expr, type, complain);
 	  }

+	if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
+	    && DECL_P (expr) && DECL_IS_BUILTIN (expr))
+	  {
+	    error_at (input_location, "taking address of a builtin function");
+	    return error_mark_node;
+	  }
+
 	/* Take the address of the thing to which we will bind the
 	   reference.  */
 	expr = cp_build_addr_expr (expr, complain);
@@ -9768,8 +9775,18 @@ initialize_reference (tree type, tree expr,
     }

   if (conv->kind == ck_ref_bind)
+    {
+      if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
+	  && DECL_P (expr) && DECL_IS_BUILTIN (expr))
+	{
+	  error_at (input_location, "invalid initialization of a reference "
+		    "with a builtin function");
+	  return error_mark_node;
+	}
+
       /* Perform the conversion.  */
       expr = convert_like (conv, expr, complain);
+    }
   else if (conv->kind == ck_ambig)
     /* We gave an error in build_user_type_conversion_1.  */
     expr = error_mark_node;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 5b09b73..fbea052 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5621,6 +5621,13 @@ cp_build_addr_expr (tree arg, tsubst_flags_t complain)
 static tree
 cp_build_addr_expr_strict (tree arg, tsubst_flags_t complain)
 {
+  if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
+      && DECL_P (arg) && DECL_IS_BUILTIN (arg))
+    {
+      error_at (input_location, "taking address of a builtin function");
+      return error_mark_node;
+    }
+
   return cp_build_addr_expr_1 (arg, 1, complain);
 }

@@ -6860,6 +6867,14 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
 	  || VOID_TYPE_P (TREE_TYPE (type))))
     return convert_member_func_to_ptr (type, expr, complain);

+  if (TREE_CODE (intype) == FUNCTION_TYPE
+      && DECL_P (expr) && DECL_IS_BUILTIN (expr))
+    {
+      error_at (EXPR_LOC_OR_LOC (expr, input_location),
+		"taking address of a builtin function");
+      return error_mark_node;
+    }
+
   /* If the cast is not to a reference type, the lvalue-to-rvalue,
      array-to-pointer, and function-to-pointer conversions are
      performed.  */
@@ -8307,6 +8322,13 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
       || (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))
     return error_mark_node;

+  if (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
+      && DECL_P (rhs) && DECL_IS_BUILTIN (rhs))
+    {
+      error_at (input_location, "taking address of a builtin function");
+      return error_mark_node;
+    }
+
   if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
        && TREE_CODE (type) != ARRAY_TYPE
        && (TREE_CODE (type) != REFERENCE_TYPE

2015-06-21  Martin Sebor  <msebor@redhat.com>

	PR c/66516
	* gcc.dg/addr_builtin-pr66516.c: New test.
	* g++.dg/addr_builtin-pr66516.C: New test.

diff --git a/gcc/testsuite/g++.dg/addr_builtin-pr66516.C b/gcc/testsuite/g++.dg/addr_builtin-pr66516.C
new file mode 100644
index 0000000..38f1a51
--- /dev/null
+++ b/gcc/testsuite/g++.dg/addr_builtin-pr66516.C
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+
+/* Verify that taking the address of a builtin function generates
+   a compilation error.  */
+
+#if 201103L <= __cplusplus
+
+bool func (void)
+{
+  /* Taking the address of builtin constants is valid.  */
+  return &__func__ == &__func__;             /* { dg-bogus "builtin" } */
+}
+
+#endif
+
+/* Calling the builtins is valid.  */
+int foo (int i)
+{
+  const void* p = 0;
+
+  switch (i & 0xf) {
+  case 0: i = __builtin_expect (i, 0);       /* { dg-bogus "builtin" } */
+  case 1: p = __builtin_return_address (0);  /* { dg-bogus "builtin" } */
+  case 2: i = __builtin_strlen ("");         /* { dg-bogus "builtin" } */
+  case 3: p = __builtin_FILE ();             /* { dg-bogus "builtin" } */
+  case 4: p = __builtin_FUNCTION ();         /* { dg-bogus "builtin" } */
+  case 5: i = __builtin_LINE ();             /* { dg-bogus "builtin" } */
+  }
+  return p ? *(int*)p : i;
+}
+
+void* const addr[] = {
+  (void*)__builtin_expect,          /* { dg-error "builtin" } */
+  (void*)__builtin_return_address,  /* { dg-error "builtin" } */
+  (void*)__atomic_load,             /* { dg-error "builtin" } */
+  (void*)__builtin_add_overflow,    /* { dg-error "builtin" } */
+  (void*)__builtin_constant_p,      /* { dg-error "builtin" } */
+  (void*)__builtin_nanf,            /* { dg-error "builtin" } */
+  (void*)__builtin_strlen,          /* { dg-error "builtin" } */
+  (void*)__builtin_unreachable,     /* { dg-error "builtin" } */
+  (void*)__builtin_FILE,            /* { dg-error "builtin" } */
+  (void*)__builtin_FUNCTION,        /* { dg-error "builtin" } */
+  (void*)__builtin_LINE,            /* { dg-error "builtin" } */
+
+  (void*)&__builtin_expect,         /* { dg-error "builtin" } */
+  (void*)&__builtin_return_address, /* { dg-error "builtin" } */
+  (void*)&__atomic_load,            /* { dg-error "builtin" } */
+  (void*)&__builtin_add_overflow,   /* { dg-error "builtin" } */
+  (void*)&__builtin_constant_p,     /* { dg-error "builtin" } */
+  (void*)&__builtin_nanf,           /* { dg-error "builtin" } */
+  (void*)&__builtin_strlen,         /* { dg-error "builtin" } */
+  (void*)&__builtin_unreachable,    /* { dg-error "builtin" } */
+  (void*)&__builtin_FILE,           /* { dg-error "builtin" } */
+  (void*)&__builtin_FUNCTION,       /* { dg-error "builtin" } */
+  (void*)&__builtin_LINE,           /* { dg-error "builtin" } */
+
+  reinterpret_cast<void*>(__builtin_expect),       /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_return_address), /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__atomic_load),          /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_add_overflow), /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_constant_p),   /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_nanf),         /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_strlen),       /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_unreachable),  /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_FILE),         /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_FUNCTION),     /* { dg-error "builtin" } */
+  reinterpret_cast<void*>(__builtin_LINE),         /* { dg-error "builtin" } */
+
+  0
+};
diff --git a/gcc/testsuite/gcc.dg/addr_builtin-pr66516.c b/gcc/testsuite/gcc.dg/addr_builtin-pr66516.c
new file mode 100644
index 0000000..b0b480e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/addr_builtin-pr66516.c
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+
+/* Verify that taking the address of a builtin function generates
+   a compilation error.  */
+
+#if 199901L <= __STDC_VERSION__
+
+int func (void)
+{
+  /* Taking the address of builtin constants is valid.  */
+  return &__func__ == &__func__;                /* { dg-bogus "builtin" } */
+}
+
+#endif
+
+
+/* Calling the builtins is valid.  */
+int foo (int i)
+{
+  const void* p = 0;
+
+  switch (i & 0xf) {
+  case 0: i = __builtin_expect (i, 0);       /* { dg-bogus "builtin" } */
+  case 1: p = __builtin_return_address (0);  /* { dg-bogus "builtin" } */
+  case 2: i = __builtin_strlen ("");         /* { dg-bogus "builtin" } */
+  case 3: p = __builtin_FILE ();             /* { dg-bogus "builtin" } */
+  case 4: p = __builtin_FUNCTION ();         /* { dg-bogus "builtin" } */
+  case 5: i = __builtin_LINE ();             /* { dg-bogus "builtin" } */
+  }
+  return p ? *(int*)p : i;
+}
+
+void* const addr[] = {
+  (void*)__builtin_expect,          /* { dg-error "builtin" } */
+  (void*)__builtin_return_address,  /* { dg-error "builtin" } */
+  (void*)__atomic_load,             /* { dg-error "builtin" } */
+  (void*)__builtin_add_overflow,    /* { dg-error "builtin" } */
+  (void*)__builtin_constant_p,      /* { dg-error "builtin" } */
+  (void*)__builtin_nanf,            /* { dg-error "builtin" } */
+  (void*)__builtin_strlen,          /* { dg-error "builtin" } */
+  (void*)__builtin_unreachable,     /* { dg-error "builtin" } */
+  (void*)__builtin_FILE,            /* { dg-error "builtin" } */
+  (void*)__builtin_FUNCTION,        /* { dg-error "builtin" } */
+  (void*)__builtin_LINE,            /* { dg-error "builtin" } */
+
+  (void*)&__builtin_expect,         /* { dg-error "builtin" } */
+  (void*)&__builtin_return_address, /* { dg-error "builtin" } */
+  (void*)&__atomic_load,            /* { dg-error "builtin" } */
+  (void*)&__builtin_add_overflow,   /* { dg-error "builtin" } */
+  (void*)&__builtin_constant_p,     /* { dg-error "builtin" } */
+  (void*)&__builtin_nanf,           /* { dg-error "builtin" } */
+  (void*)&__builtin_strlen,         /* { dg-error "builtin" } */
+  (void*)&__builtin_unreachable,    /* { dg-error "builtin" } */
+  (void*)&__builtin_FILE,           /* { dg-error "builtin" } */
+  (void*)&__builtin_FUNCTION,       /* { dg-error "builtin" } */
+  (void*)&__builtin_LINE,           /* { dg-error "builtin" } */
+
+  0
+};

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]