PR c/81854 - weak alias of an incompatible symbol accepted
authorMartin Sebor <msebor@redhat.com>
Tue, 19 Sep 2017 14:27:32 +0000 (14:27 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Tue, 19 Sep 2017 14:27:32 +0000 (08:27 -0600)
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.

From-SVN: r252976

gcc/ChangeLog
gcc/cgraphunit.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
gcc/testsuite/g++.dg/ext/attr-ifunc-5.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
gcc/testsuite/gcc.dg/attr-ifunc-1.c
gcc/testsuite/gcc.dg/pr81854.c [new file with mode: 0644]

index d2a7c14a8731fbb620080827c62ca8af94937bae..e08ae4c3f4aa90f85330b40596dcb6dec89c3a5a 100644 (file)
@@ -1,3 +1,9 @@
+2017-09-18  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81854
+       * cgraphunit.c (handle_alias_pairs): Reject aliases between functions
+       of incompatible types.
+
 2017-09-19  Will Schmidt  <will_schmidt@vnet.ibm.com>
 
        * config/rs6000/rs6000.c (rs6000_gimple_fold_builtin): Add handling
index a287f0dfd44357e3e55a4f226fa131c1324cbf56..8c1acf770b9166937175a84c4354ef4ad2081792 100644 (file)
@@ -1352,6 +1352,66 @@ 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))))
+           {
+             /* Warn for incompatibilities.  Avoid warning for functions
+                without a prototype to make it possible to declare aliases
+                without knowing the exact type, as libstdc++ does.  */
+             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 +1426,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);
        }
     }
index a69bce3177f00208d52087631323410cb22d0634..27fc7bad75255c78c4befb28461179b8be088a74 100644 (file)
@@ -1,3 +1,15 @@
+2017-09-18  Martin Sebor  <msebor@redhat.com>
+
+       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.
+
 2017-09-19  Will Schmidt  <will_schmidt@vnet.ibm.com>
 
        * gcc.target/powerpc/fold-vec-ld-misc.c: New.
index d41fa7d3267c84d5ffa8143d0f0edf321bfcbde1..2c7bba129597aa63a1c59e45e54ad65acb553797 100644 (file)
@@ -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);
 }
index e205a2a6a8d5d531a15b65bc536d900e0ef4c202..49872e0cbeaed2a4f9e4713d9b2396e6cb56b777 100644 (file)
@@ -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;
 }
index ba65976b96495ada26562c7fb2ecceef713fca10..04206a126e8e290981226a1a9a92402bf42a6fd1 100644 (file)
@@ -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;
 }
index 0cae41028b5d9c3d35a3995860df6b9ce66a97e1..b8d8e5879b4cce3f5fa6c35edc8ff31e6d251a38 100644 (file)
@@ -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 (file)
index 0000000..05855dd
--- /dev/null
@@ -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;
+}
index 30228756f12752d64be676761c2fde47825c432b..2c88a95800bc0e2b827f954a6ceebbf113869808 100644 (file)
@@ -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")));
 }
index f9c6482298c70a11bbeff85fe2f7288c9e7887dd..3f7450e2c699ab9e964c9e1b2f5bdf32c8e2e221 100644 (file)
@@ -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 (file)
index 0000000..4b0f4da
--- /dev/null
@@ -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;
+}