On 02/16/2018 01:38 AM, Jakub Jelinek wrote:
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.
The deeper problem is that vec wants to be a POD but GCC
instantiates the template on non-POD types. For example
genrecog.c instantiates it on struct parameter that has
a default ctor.
A number of ipa-*.c files instantiate vec on
ipa_polymorphic_call_context, which also has a default ctor,
and ctor even has different semantics than memset (it sets
a few members to non-zero). So calling memset here instead
of the default ctor could be a potential bug.
Martin
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