Hi!

As the system.h comment says, it took us years to get value initialization
right, and unfortunately we've started hitting it in GCC codebase now.
There are various related PRs, 4.2.[0-3] are most broken in this regard,
value initialization of non-PODs doesn't actually initialize there anything,
but https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84405#c5 shows a testcase
where any GCC < 4.3 just calls the default ctor for the
*entries = value_type ();
in hash-table.h even when value_type has no user provided ctor, and one
pointer field and another field with user provided ctor.  We want to
zero initialize the pointer and default initialize the other field, but
< 4.3 just default initializes the other field and pointer (m_key) remains
uninitialized.
The vec_default_construct case can hit another bug in < 4.4, if we have a
similar class with multiple fields and at least one of them with user provided
ctor, and at least one of them without user provided ctor, the new T ()
default initializes it rather than value initializes it.

The following patch provides sufficient workaround so that GCC 3.4.6 as a
system compiler can bootstrap GCC (haven't tested other versions).  It is
not enough to get GCC 4.2.[0-3] usable as bootstrap compiler, either we add
2-3 further workarounds, or just reject GCC >= 4.2.0 and <= 4.2.3 in
configure.

Ok for trunk?

2018-02-16  Jakub Jelinek  <ja...@redhat.com>

        PR bootstrap/84405
        * system.h (BROKEN_VALUE_INITIALIZATION): Define for GCC < 4.3.
        * vec.h (vec_default_construct): Use memset instead of placement new
        if BROKEN_VALUE_INITIALIZATION is defined.
        * hash-table.h (hash_table<Descriptor, Allocator>::empty_slow): Use
        memset instead of value initialization if BROKEN_VALUE_INITIALIZATION
        is defined.

--- gcc/system.h.jj     2018-01-03 10:19:54.530533857 +0100
+++ gcc/system.h        2018-02-15 21:56:37.168139415 +0100
@@ -824,6 +824,12 @@ extern void fancy_abort (const char *, i
 /* Some compilers do not allow the use of unsigned char in bitfields.  */
 #define BOOL_BITFIELD unsigned int
 
+/* GCC older than 4.4 have broken C++ value initialization handling, see
+   PR11309, PR30111, PR33916, PR82939 and PR84405 for more details.  */
+#if GCC_VERSION > 0 && GCC_VERSION < 4004 && !defined(__clang__)
+# define BROKEN_VALUE_INITIALIZATION
+#endif
+
 /* As the last action in this file, we poison the identifiers that
    shouldn't be used.  Note, luckily gcc-3.0's token-based integrated
    preprocessor won't trip on poisoned identifiers that arrive from
--- gcc/vec.h.jj        2018-01-03 10:19:54.606533869 +0100
+++ gcc/vec.h   2018-02-15 22:00:36.386216876 +0100
@@ -490,8 +490,12 @@ template <typename T>
 inline void
 vec_default_construct (T *dst, unsigned n)
 {
+#ifndef BROKEN_VALUE_INITIALIZATION
   for ( ; n; ++dst, --n)
     ::new (static_cast<void*>(dst)) T ();
+#else
+  memset (dst, '\0', sizeof (T) * n);
+#endif
 }
 
 /* Copy-construct N elements in DST from *SRC.  */
--- gcc/hash-table.h.jj 2018-01-03 10:19:54.899533916 +0100
+++ gcc/hash-table.h    2018-02-15 21:58:14.449170915 +0100
@@ -804,8 +804,12 @@ hash_table<Descriptor, Allocator>::empty
     }
   else
     {
+#ifndef BROKEN_VALUE_INITIALIZATION
       for ( ; size; ++entries, --size)
        *entries = value_type ();
+#else
+      memset (entries, 0, size * sizeof (value_type));
+#endif
     }
   m_n_deleted = 0;
   m_n_elements = 0;

        Jakub

Reply via email to