public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] detect incompatible aliases (PR c/81854)
@ 2017-08-18  8:10 Martin Sebor
  2017-08-18 13:10 ` Joseph Myers
                   ` (4 more replies)
  0 siblings, 5 replies; 29+ messages in thread
From: Martin Sebor @ 2017-08-18  8:10 UTC (permalink / raw)
  To: Gcc Patch List, Joseph Myers, Jonathan Wakely, libstdc++

[-- Attachment #1: Type: text/plain, Size: 2465 bytes --]

Joseph, while looking into implementing enhancement your request
pr81824 I noticed that GCC silently accepts incompatible alias
declarations (pr81854) so as sort of a proof-concept for the
former I enhanced the checking already done for other kinds of
incompatibilities to also detect those mentioned in the latter
bug.  Attached is this patch, tested on x85_64-linux.

Jonathan, the patch requires suppressing the warning in libstdc++
compatibility symbol definitions in compatibility.cc.  I couldn't
find a way to do it without the suppression but I'd be happy to
try again if you have an idea for how.

As an example, the patch lets GCC detect mistakes like:

    size_t __attribute__ ((ifunc ("bar_resolver")))
    bar (void*, const void*, size_t);

    void* fast_bar (void *d, const void *s, size_t n) { ... }
    void* slow_bar (void *d, const void *s, size_t n) { ... }

    void* bar_resolver (void)
    {
       return fast ? &fast_bar : &slow_bar;
    }

By complaining that the ifunc resolver should return a function
pointer it makes the programmer change the declaration of the
resolver to one of:

    __typeof__ (bar)* bar_resolver (void) { ... }

or

    __typeof__ (fast_bar)* bar_resolver (void) { ... }

which then triggers either -Wincompatible-pointer-types or
-Wattributes, respectively.  (I used the latter warning in
my patch but maybe the former would be more appropriate).

Martin

PS A documentation-only patch to update the description of
attribute ifunc was posted separately here:
    https://gcc.gnu.org/ml/gcc-patches/2017-08/msg01095.html

PPS To make use of this checking (and compile without the new
warnings) Glibc needs the following patch:

diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index fe3ab81..5413e56 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -790,7 +790,8 @@ for linking")

  /* Helper / base  macros for indirect function symbols.  */
  #define __ifunc_resolver(type_name, name, expr, arg, init, classifier) \
-  classifier inhibit_stack_protector void *name##_ifunc (arg) 
                        \
+  classifier inhibit_stack_protector                                   \
+  __typeof (type_name) *name##_ifunc (arg)                             \
    {                                                                    \
      init ();                                                           \
      __typeof (type_name) *res = expr;                                  \


[-- Attachment #2: gcc-81854.diff --]
[-- Type: text/x-patch, Size: 12313 bytes --]

PR c/81854 - weak alias of an incompatible symbol accepted

gcc/ChangeLog:

	PR c/81854
	* cgraphunit.c (handle_alias_pairs): Reject aliases between functions
	of incompatible types.

gcc/testsuite/ChangeLog:

	PR c/81854
	* gcc.dg/pr81854.c: New test.
	* g++.dg/ext/attr-ifunc-5.C: New test.
	* g++.dg/ext/attr-ifunc-1.C: Adjust.
	* g++.dg/ext/attr-ifunc-2.C: Same.
	* g++.dg/ext/attr-ifunc-3.C: Same.
	* g++.dg/ext/attr-ifunc-4.C: Same.
	* g++.old-deja/g++.abi/vtable2.C: Same.
	* gcc.dg/attr-ifunc-1.c: Same.

libstdc++-v3/ChangeLog:

	PR c/81854
	* src/c++98/compatibility.cc: Suppress -Wattributes.

diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index e8cc765..8d09a79 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -1352,6 +1352,63 @@ handle_alias_pairs (void)
       if (TREE_CODE (p->decl) == FUNCTION_DECL
           && target_node && is_a <cgraph_node *> (target_node))
 	{
+	  tree t1 = TREE_TYPE (p->decl);
+	  tree t2 = TREE_TYPE (target_node->decl);
+
+	  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (p->decl)))
+	    {
+	      t2 = TREE_TYPE (t2);
+	      if (POINTER_TYPE_P (t2))
+		{
+		  t2 = TREE_TYPE (t2);
+		  if (!FUNC_OR_METHOD_TYPE_P (t2))
+		    {
+		      if (warning_at (DECL_SOURCE_LOCATION (p->decl),
+				      OPT_Wattributes,
+				      "%q+D %<ifunc%> resolver should return "
+				      "a function pointer",
+				      p->decl))
+			inform (DECL_SOURCE_LOCATION (target_node->decl),
+				"resolver declaration here");
+
+		      t2 = NULL_TREE;
+		    }
+		}
+	      else
+		{
+		  /* Deal with static member function pointers.  */
+		  if (TREE_CODE (t2) == RECORD_TYPE
+		      && TYPE_FIELDS (t2)
+		      && TREE_CODE (TREE_TYPE (TYPE_FIELDS (t2))) == POINTER_TYPE
+		      && (TREE_CODE (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (t2))))
+			  == METHOD_TYPE))
+		    t2 = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (t2)));
+		  else
+		    {
+		      error ("%q+D %<ifunc%> resolver must return a function "
+			     "pointer",
+			     p->decl);
+		      inform (DECL_SOURCE_LOCATION (target_node->decl),
+			      "resolver declaration here");
+
+		      t2 = NULL_TREE;
+		    }
+		}
+	    }
+
+	  if (t2
+	      && (!FUNC_OR_METHOD_TYPE_P (t2)
+		  || (prototype_p (t1)
+		      && prototype_p (t2)
+		      && !types_compatible_p (t1, t2))))
+	    {
+	      if (warning_at (DECL_SOURCE_LOCATION (p->decl), OPT_Wattributes,
+			      "%q+D alias between functions of incompatible "
+			      "types %qT and %qT", p->decl, t1, t2))
+		inform (DECL_SOURCE_LOCATION (target_node->decl),
+			"aliased declaration here");
+	    }
+
 	  cgraph_node *src_node = cgraph_node::get (p->decl);
 	  if (src_node && src_node->definition)
 	    src_node->reset ();
@@ -1366,10 +1423,11 @@ handle_alias_pairs (void)
 	}
       else
 	{
-	  error ("%q+D alias in between function and variable is not supported",
+	  error ("%q+D alias between function and variable is not supported",
 		 p->decl);
-	  warning (0, "%q+D aliased declaration",
-		   target_node->decl);
+	  inform (DECL_SOURCE_LOCATION (target_node->decl),
+		  "aliased declaration here");
+
 	  alias_pairs->unordered_remove (i);
 	}
     }
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
index d41fa7d..2c7bba1 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
@@ -2,33 +2,41 @@
 /* { dg-require-ifunc "" } */
 /* { dg-options "-Wno-pmf-conversions" } */
 
-#include <stdio.h>
-
 struct Klass
 {
   int implementation ();
   int magic ();
-  static void *resolver ();
+
+  typedef int (Klass::*MemFuncPtr)();
+
+  static MemFuncPtr resolver ();
 };
 
+Klass::MemFuncPtr p = &Klass::implementation;
+
 int Klass::implementation (void)
 {
-  printf ("'ere I am JH\n");
-  return 0;
+  __builtin_printf ("'ere I am JH\n");
+  return 1234;
 }
 
-void *Klass::resolver (void)
+
+Klass::MemFuncPtr Klass::resolver (void)
 {
-  int (Klass::*pmf) () = &Klass::implementation;
-  
-  return (void *)(int (*)(Klass *))(((Klass *)0)->*pmf);
+  return &Klass::implementation;
 }
 
+int f (void) __attribute__ ((ifunc ("foo")));
+
+typedef int (F)(void);
+extern "C" F* foo () { return 0; }
+
+
 int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
 
 int main ()
 {
   Klass obj;
-  
-  return obj.magic () != 0;
+
+  return !(obj.magic () == 1234);
 }
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
index e205a2a..49872e0 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
@@ -8,7 +8,10 @@ struct Klass
 {
   int implementation ();
   int magic ();
-  static void *resolver ();
+
+  typedef int (Klass::*MemFuncPtr)();
+
+  static MemFuncPtr resolver ();
 };
 
 int Klass::implementation (void)
@@ -17,11 +20,9 @@ int Klass::implementation (void)
   return 0;
 }
 
-void *Klass::resolver (void)
+Klass::memFuncPtr Klass::resolver (void)
 {
-  int (Klass::*pmf) () = &Klass::implementation;
-  
-  return (void *)(int (*)(Klass *))(((Klass *)0)->*pmf);
+  return &Klass::implementation;
 }
 
 int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
@@ -33,6 +34,6 @@ struct Klassier : Klass
 int main ()
 {
   Klassier obj;
-  
+
   return obj.magic () != 0;
 }
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
index ba65976..04206a1 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
@@ -8,7 +8,10 @@ struct Klass
 {
   int implementation ();
   int magic ();
-  static void *resolver ();
+
+  typedef int (Klass::*MemFuncPtr)();
+
+  static MemFuncPtr resolver ();
 };
 
 int Klass::implementation (void)
@@ -17,11 +20,9 @@ int Klass::implementation (void)
   return 0;
 }
 
-void *Klass::resolver (void)
+Klass::MemFuncPtr Klass::resolver (void)
 {
-  int (Klass::*pmf) () = &Klass::implementation;
-  
-  return (void *)(int (*)(Klass *))(((Klass *)0)->*pmf);
+  return &Klass::implementation;
 }
 
 int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
@@ -34,6 +35,6 @@ int Foo (Klass &obj, int (Klass::*pmf) ())
 int main ()
 {
   Klass obj;
-  
+
   return Foo (obj, &Klass::magic) != 0;
 }
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
index 0cae410..b8d8e58 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
@@ -13,7 +13,10 @@ struct Klassier : Klass
 {
   int implementation ();
   int magic ();
-  static void *resolver ();
+
+  typedef int (Klass::*MemFuncPtr)();
+
+  static MemFuncPtr resolver ();
 };
 
 int Klassier::implementation (void)
@@ -22,11 +25,9 @@ int Klassier::implementation (void)
   return 0;
 }
 
-void *Klassier::resolver (void)
+Klassier::MemFuncPtr Klassier::resolver (void)
 {
-  int (Klassier::*pmf) () = &Klassier::implementation;
-  
-  return (void *)(int (*)(Klassier *))(((Klassier *)0)->*pmf);
+  return &Klassier::implementation;
 }
 
 int Klassier::magic (void) __attribute__ ((ifunc ("_ZN8Klassier8resolverEv")));
@@ -39,6 +40,6 @@ int __attribute__ ((weak)) Foo (Klass &base)
 int main ()
 {
   Klassier obj;
-  
+
   return Foo (obj) != 0;
 }
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C
new file mode 100644
index 0000000..05855dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C
@@ -0,0 +1,29 @@
+// PR c/81854 - weak alias of an incompatible symbol accepted
+// { dg-do compile }
+// { dg-require-ifunc "" } */
+
+struct Klass
+{
+  int implementation ();
+  const char* magic ();
+
+  typedef int (Klass::*MemFuncPtr)();
+
+  static MemFuncPtr resolver ();
+};
+
+int Klass::implementation (void)
+{
+  return 0;
+}
+
+const char* __attribute__ ((ifunc ("_ZN5Klass8resolverEv")))
+  Klass::magic ();   // { dg-warning "alias between functions of incompatible types" }
+
+
+
+Klass::MemFuncPtr
+Klass::resolver (void) // { dg-message "aliased declaration here" }
+{
+  return &Klass::implementation;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
index 3022875..2c88a95 100644
--- a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
+++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
@@ -1,5 +1,5 @@
 // { dg-do run  }
-// { dg-options "-fno-strict-aliasing" }
+// { dg-options "-Wno-attributes -fno-strict-aliasing" }
 // Origin: Mark Mitchell <mark@codesourcery.com>
 
 #if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
@@ -126,7 +126,8 @@ void S4::s1 ()
 extern "C" {
   /* We can use weakref here without dg-require-weak, because we know
      the symbols are defined, so we don't actually issue the .weak
-     directives.  */
+     directives.  The references to the incompatible virtual S3::s3()
+     and S4::s1() trigger -Wattributes.  */
   static void S3_s3 () __attribute__((__weakref__ ("_ZN2S32s3Ev")));
   static void S4_s1 () __attribute__((__weakref__ ("_ZN2S42s1Ev")));
 }
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-1.c b/gcc/testsuite/gcc.dg/attr-ifunc-1.c
index f9c6482..3f7450e 100644
--- a/gcc/testsuite/gcc.dg/attr-ifunc-1.c
+++ b/gcc/testsuite/gcc.dg/attr-ifunc-1.c
@@ -2,17 +2,17 @@
 /* { dg-require-ifunc "" } */
 /* { dg-options "" } */
 
-#include <stdio.h>
+typedef int F (void);
 
 static int implementation (void)
 {
-  printf ("'ere I am JH\n");
+  __builtin_printf ("'ere I am JH\n");
   return 0;
 }
 
-static void *resolver (void)
+static F* resolver (void)
 {
-  return (void *)implementation;
+  return implementation;
 }
 
 extern int magic (void) __attribute__ ((ifunc ("resolver")));
diff --git a/gcc/testsuite/gcc.dg/pr81854.c b/gcc/testsuite/gcc.dg/pr81854.c
new file mode 100644
index 0000000..4b0f4da
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr81854.c
@@ -0,0 +1,63 @@
+/* PR c/81854 - weak alias of an incompatible symbol accepted
+   { dg-do compile } */
+
+const char* __attribute__ ((weak, alias ("f0_target")))
+f0 (void);          /* { dg-error "alias between function and variable" } */
+
+int f0_target;      /* { dg-message "aliased declaration here" } */
+
+
+const char* __attribute__ ((weak, alias ("f1_target")))
+f1 (void);          /* { dg-warning "alias between functions of incompatible types" } */
+
+void f1_target (int *p)   /* { dg-message "aliased declaration here" } */
+{
+  *p = 0;
+}
+
+
+const char* __attribute__ ((alias ("f2_target")))
+f2 (void*);   /* { dg-warning "alias between functions of incompatible types" } */
+
+const char* f2_target (int i)   /* { dg-message "aliased declaration here" } */
+{
+  (void)&i;
+  return 0;
+}
+
+
+int __attribute__ ((ifunc ("f3_resolver")))
+f3 (void);          /* { dg-error ".ifunc. resolver must return a function pointer" } */
+
+int f3_resolver (void)   /* { dg-message "resolver declaration here" } */
+{
+  return 0;
+}
+
+
+int __attribute__ ((ifunc ("f4_resolver")))
+f4 (void);          /* { dg-warning ".ifunc. resolver should return a function pointer" } */
+
+void* f4_resolver (void) /* { dg-message "resolver declaration here" } */
+{
+  return 0;
+}
+
+
+int __attribute__ ((ifunc ("f5_resolver")))
+f5 (void);          /* { dg-warning "alias between functions of incompatible types" } */
+
+typedef void F5 (void);
+F5* f5_resolver (void) /* { dg-message "aliased declaration here" } */
+{
+  return 0;
+}
+
+const char* __attribute__ ((ifunc ("f6_resolver")))
+f6 (void);
+
+typedef const char* F6 (void);
+F6* f6_resolver (void)
+{
+  return 0;
+}
diff --git a/libstdc++-v3/src/c++98/compatibility.cc b/libstdc++-v3/src/c++98/compatibility.cc
index 381f4c4..5f56b9e 100644
--- a/libstdc++-v3/src/c++98/compatibility.cc
+++ b/libstdc++-v3/src/c++98/compatibility.cc
@@ -213,6 +213,11 @@ _ZNSt19istreambuf_iteratorIcSt11char_traitsIcEEppEv
 _ZNSt19istreambuf_iteratorIwSt11char_traitsIwEEppEv
  */
 
+// Disable warning about declaring aliases between functions with
+// incompatible types.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattributes"
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -509,6 +514,9 @@ _GLIBCXX_MATHL_WRAPPER1 (tan, GLIBCXX_3.4);
 #endif
 #endif // _GLIBCXX_LONG_DOUBLE_COMPAT
 
+// Restore disable -Wattributes
+#pragma GCC diagnostic pop
+
 #endif
 
 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2017-10-03 23:43 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-18  8:10 [PATCH] detect incompatible aliases (PR c/81854) Martin Sebor
2017-08-18 13:10 ` Joseph Myers
2017-08-18 13:57 ` Jonathan Wakely
2017-08-18 18:22   ` Martin Sebor
2017-08-18 18:37     ` Jonathan Wakely
2017-08-18 21:02       ` Martin Sebor
2017-09-02 22:50 ` [PING] " Martin Sebor
2017-09-12 16:17 ` Joseph Myers
2017-09-18 21:21   ` Martin Sebor
2017-09-18 21:44     ` Joseph Myers
2017-09-19 15:16       ` Martin Sebor
2017-09-20 15:37         ` Steve Ellcey
2017-09-20 16:17           ` Martin Sebor
2017-09-20 16:38             ` Steve Ellcey
2017-09-20 17:23               ` Steve Ellcey
2017-09-20 17:32               ` Martin Sebor
2017-09-20 17:45                 ` Steve Ellcey
2017-09-20 18:05                   ` Joseph Myers
2017-09-20 18:01                 ` Joseph Myers
2017-09-20 18:08                   ` Steve Ellcey
2017-09-20 18:14                     ` Joseph Myers
2017-09-20 21:01                     ` Joseph Myers
2017-09-20 21:32                   ` Martin Sebor
2017-09-20 21:45                     ` Joseph Myers
2017-10-02 19:49           ` Steve Ellcey
2017-10-02 19:53             ` Joseph Myers
2017-10-02 20:17             ` Martin Sebor
2017-10-03 21:41 ` Andreas Schwab
2017-10-03 23:43   ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).