compiler: use SHA1-hash for symname for long gcbits symbols
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 17 May 2019 13:48:18 +0000 (13:48 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 17 May 2019 13:48:18 +0000 (13:48 +0000)
    The current scheme used by the compiler for "gcbits" symbols involves
    generating a symbol name based on a 32-char encoding of the bits data.
    This scheme works well in most cases but can generate very long symbol
    names in rare cases. To help avoid such long symbol names, switch to a
    different encoding scheme based on the SHA1 digest of the payload if
    the symbol size would be too large.

    Fixes golang/go#32083.

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/177598

From-SVN: r271322

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/types.cc

index 304c910b2d01138bce6542bc59ba4c6213a7dfee..2cd7a0e94fec899ec83f1c1f177faba812b91734 100644 (file)
@@ -1,4 +1,4 @@
-b5ab7b419d6328f5126ba8d6795280129eaf6e79
+54aacecc8167bfba8420cb7b245787ff80bde61b
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 52606261833cef446da1c06d43e7f0f69d97e0ea..f6c104cef8a23b59669929c7563277ad54ca55d5 100644 (file)
@@ -12,6 +12,7 @@
 #include "gogo.h"
 #include "go-diagnostics.h"
 #include "go-encode-id.h"
+#include "go-sha1.h"
 #include "operator.h"
 #include "expressions.h"
 #include "statements.h"
@@ -2776,22 +2777,43 @@ Ptrmask::set_from(Gogo* gogo, Type* type, int64_t ptrsize, int64_t offset)
     }
 }
 
-// Return a symbol name for this ptrmask.  This is used to coalesce
-// identical ptrmasks, which are common.  The symbol name must use
-// only characters that are valid in symbols.  It's nice if it's
-// short.  We convert it to a string that uses only 32 characters,
-// avoiding digits and u and U.
-
+// Return a symbol name for this ptrmask. This is used to coalesce identical
+// ptrmasks, which are common. The symbol name must use only characters that are
+// valid in symbols. It's nice if it's short. For smaller ptrmasks, we convert
+// it to a string that uses only 32 characters, avoiding digits and u and U. For
+// longer pointer masks, apply the same process to the SHA1 digest of the bits,
+// so as to avoid pathologically long symbol names (see related Go issues #32083
+// and #11583 for more on this). To avoid collisions between the two encoding
+// schemes, use a prefix ("X") for the SHA form to disambiguate.
 std::string
 Ptrmask::symname() const
 {
+  const std::vector<unsigned char>* bits(&this->bits_);
+  std::vector<unsigned char> shabits;
+  std::string prefix;
+
+  if (this->bits_.size() > 128)
+    {
+      // Produce a SHA1 digest of the data.
+      Go_sha1_helper* sha1_helper = go_create_sha1_helper();
+      sha1_helper->process_bytes(&this->bits_[0], this->bits_.size());
+      std::string digest = sha1_helper->finish();
+      delete sha1_helper;
+
+      // Redirect the bits vector to the digest, and update the prefix.
+      prefix = "X";
+      for (char c : digest)
+        shabits.push_back((unsigned char) c);
+      bits = &shabits;
+    }
+
   const char chars[33] = "abcdefghijklmnopqrstvwxyzABCDEFG";
   go_assert(chars[32] == '\0');
-  std::string ret;
+  std::string ret(prefix);
   unsigned int b = 0;
   int remaining = 0;
-  for (std::vector<unsigned char>::const_iterator p = this->bits_.begin();
-       p != this->bits_.end();
+  for (std::vector<unsigned char>::const_iterator p = bits->begin();
+       p != bits->end();
        ++p)
     {
       b |= *p << remaining;