On Thu, Feb 21, 2019 at 1:57 AM Richard Biener
<richard.guent...@gmail.com> wrote:
>
> On Wed, Feb 20, 2019 at 6:53 PM Ian Lance Taylor <i...@golang.org> wrote:
> >
> > The underlying cause of PR 89170 is a bug that appears to have existed
> > since 2001, when the function decode_addr_const was changed to call
> > output_constant_def.  The problem is that output_constant_def calls
> > compare_constant, and when compare_constant sees an ADDR_EXPR, it
> > calls decode_addr_const.  So it is possible for output_constant_def to
> > call itself recursively while adding a value to the hash table.  This
> > only happens if there are already some constants in the hash table
> > with the same hash code, because that is the only case in which
> > compare_constant can call decode_addr_constant.  This works fine if
> > the value whose address is taken is already in the hash table.  And it
> > works fine if the address is not in the hash table, but adding the
> > address does not cause the hash table to grow.
> >
> > But if we call output_constant_def with a constant that includes an
> > ADDR_EXPR, and if there is already a constant in the hash table with
> > the same hash code, and if decode_addr_constant calls
> > output_constant_def recursively with a constant that is not already in
> > the hash table, and if adding that constant causes the hash table to
> > grow, then the outer call to output_constant_def will wind up looking
> > at the wrong hash bucket.  The effect is that output_constant_def will
> > return an rtx for a different constant.
> >
> > This unlikely sequence of events actually happened building libgo's
> > net/http test on PPC64, causing a miscompilation leading to a test
> > failure filed as PR 89170.
> >
> > I plan to commit this patch to fix the problem.  I didn't add a test
> > case since the sequence of events is so hard to recreate.  I added a
> > check that will detect any future recursive insertion into the hash
> > table.
> >
> > Bootstrapped and tested on x86_64-pc-linux-gnu.  Since I haven't
> > looked at this part of the code in many years, I'll wait a bit to see
> > if anybody has any comments on the patch.
>
> Looks reasonable.  Factoring the common code in
> output_constant_def and tree_output_constant_def might be
> worth it.

Makes sense.  Done.  Rebootstrapped, retested, and committed as follows.

Ian

2019-02-21  Ian Lance Taylor  <i...@golang.org>

PR go/89170
* varasm.c (decode_addr_const): Call lookup_constant_def rather
than output_constant_def.
(add_constant_to_table): New static function.
(output_constant_def): Call add_constant_to_table.
(tree_output_constant_def): Likewise.
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c        (revision 268949)
+++ gcc/varasm.c        (working copy)
@@ -2961,7 +2961,9 @@ decode_addr_const (tree exp, struct addr
     case COMPLEX_CST:
     case CONSTRUCTOR:
     case INTEGER_CST:
-      x = output_constant_def (target, 1);
+      x = lookup_constant_def (target);
+      /* Should have been added by output_addressed_constants.  */
+      gcc_assert (x);
       break;
 
     case INDIRECT_REF:
@@ -3424,6 +3426,43 @@ build_constant_desc (tree exp)
   return desc;
 }
 
+/* Subroutine of output_constant_def and tree_output_constant_def:
+   Add a constant to the hash table that tracks which constants
+   already have labels.  */
+
+static constant_descriptor_tree *
+add_constant_to_table (tree exp)
+{
+  /* The hash table methods may call output_constant_def for addressed
+     constants, so handle them first.  */
+  output_addressed_constants (exp);
+
+  /* Sanity check to catch recursive insertion.  */
+  static bool inserting;
+  gcc_assert (!inserting);
+  inserting = true;
+
+  /* Look up EXP in the table of constant descriptors.  If we didn't
+     find it, create a new one.  */
+  struct constant_descriptor_tree key;
+  key.value = exp;
+  key.hash = const_hash_1 (exp);
+  constant_descriptor_tree **loc
+    = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
+
+  inserting = false;
+
+  struct constant_descriptor_tree *desc = *loc;
+  if (!desc)
+    {
+      desc = build_constant_desc (exp);
+      desc->hash = key.hash;
+      *loc = desc;
+    }
+
+  return desc;
+}
+
 /* Return an rtx representing a reference to constant data in memory
    for the constant expression EXP.
 
@@ -3440,24 +3479,7 @@ build_constant_desc (tree exp)
 rtx
 output_constant_def (tree exp, int defer)
 {
-  struct constant_descriptor_tree *desc;
-  struct constant_descriptor_tree key;
-
-  /* Look up EXP in the table of constant descriptors.  If we didn't find
-     it, create a new one.  */
-  key.value = exp;
-  key.hash = const_hash_1 (exp);
-  constant_descriptor_tree **loc
-    = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
-
-  desc = *loc;
-  if (desc == 0)
-    {
-      desc = build_constant_desc (exp);
-      desc->hash = key.hash;
-      *loc = desc;
-    }
-
+  struct constant_descriptor_tree *desc = add_constant_to_table (exp);
   maybe_output_constant_def_contents (desc, defer);
   return desc->rtl;
 }
@@ -3591,25 +3613,8 @@ lookup_constant_def (tree exp)
 tree
 tree_output_constant_def (tree exp)
 {
-  struct constant_descriptor_tree *desc, key;
-  tree decl;
-
-  /* Look up EXP in the table of constant descriptors.  If we didn't find
-     it, create a new one.  */
-  key.value = exp;
-  key.hash = const_hash_1 (exp);
-  constant_descriptor_tree **loc
-    = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
-
-  desc = *loc;
-  if (desc == 0)
-    {
-      desc = build_constant_desc (exp);
-      desc->hash = key.hash;
-      *loc = desc;
-    }
-
-  decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0));
+  struct constant_descriptor_tree *desc = add_constant_to_table (exp);
+  tree decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0));
   varpool_node::finalize_decl (decl);
   return decl;
 }

Reply via email to