Hi,

looks like there is an ugly bug in g++ front-end.

the problem can be demonstrated by the existing testcase:
ext/pb_ds/regression/trie_data_map_rand.cc

if you apply the following diff:
.../libstdc++-v3/testsuite/util/regression/rand/assoc/detail/ $ svn di
Index: insert_fn_imps.hpp
===================================================================
--- insert_fn_imps.hpp  (revision 10694)
+++ insert_fn_imps.hpp  (working copy)
@@ -58,6 +58,7 @@
         value_type v = test_traits::generate_value(m_g, m_m);
         m_alloc.set_throw_prob(m_tp);
         const_key_reference r_k = test_traits::extract_key(v);
+        std::cerr << (int*)0xDEADbeaf << std::endl;
         typename cntnr::const_point_iterator found_it = m_p_c->find(r_k);
         const bool existed = (found_it != m_p_c->end());
         const std::pair<typename cntnr::point_iterator, bool> ins_ret =
m_p_c->insert(v);

trie_data_map_rand.cc will fail on sparc and x86 after random number
of 'deadbeaf' printouts compiled with -O0.
Looks like at least 4.2.x and most recent trunk are affected.

Look into the -fdump-tree-gimple dump for the following function:
static typename Cntnr::const_key_reference
pb_ds::test::detail::regression_test_type_traits<Cntnr>::extract_key
(typename Cntnr::const_reference)
there you'll see that temporary object of 'struct pair' is created
and it's address passed into extract_key_imp() function.

The source code comes from here:
.../libstdc++-v3/testsuite/util/regression/trait/assoc/ $ svn di
Index: type_trait.hpp
===================================================================
--- type_trait.hpp      (revision 10694)
+++ type_trait.hpp      (working copy)
@@ -79,7 +79,7 @@

        static const_key_reference
         extract_key(const_reference r_val)
-       { return extract_key_imp(r_val); }
+       { return extract_key_imp(r_val); } // bug here

       private:
        typedef typename cntnr::allocator::template rebind<basic_type>::other


The mechanism of the bug is the following:
"r_k = test_traits::extract_key(v);" in insert_fn_imps.hpp eventually calls
"extract_key()" from type_trait.hpp above which creates a temp variable of
type "struct pair<basic_type,basic_type>" on stack and calls extract_key_imp()
with the address of that variable.
The returned address is actually the address of that stack temp variable,
so at the end 'r_k' points to already freed stack space.
Without '0xDEADbeaf' printout "m_p_c->find(r_k);" has a shorter
call chain than "extract_key()" and "find(r_k)" doesn't overwrite that
stack space, 'r_k' value is valid and everything works.
'deadbeaf' printout reuses that stack space and when it comes to
"m_p_c->find(r_k)", 'r_k' points to trash and 'find' sooner or later
coredumps.

Unfortunately I wasn't able to create a shorter testcase out of
trie_data_map_rand.cc
Various combination of
detail::regression_test_type_traits<s>::extract_key (ref);
with different 's' and 'ref' didn't expose the creation of such
extra temp variable.

As the summary 'extract_key' is supposed to look like:

static typename Cntnr::const_key_reference
pb_ds::test::detail::regression_test_type_traits<Cntnr>::extract_key
(typename Cntnr::const_reference) [with Cntnr = ...] (r_val)
{
  const struct basic_type & D.82957;
  const struct basic_type & D.82958;

  D.82958 = extract_key_imp (r_val);
  D.82957 = D.82958;
  return D.82957;
}

incorrect 'extract_key' may look like:

static typename Cntnr::const_key_reference
pb_ds::test::detail::regression_test_type_traits<Cntnr>::extract_key
(typename Cntnr::const_reference) [with Cntnr = ...] (r_val)
{
  const struct basic_type & D.107098;
  const struct pair D.107097;
  struct pair * D.107099;
  const struct basic_type & D.107100;

  __comp_ctor  (&D.107097, r_val);
  try
    {
      D.107100 = extract_key_imp (&D.107097);
      D.107098 = D.107100;
      return D.107098;
    }
  finally
    {
      D.107099 = (struct pair *) &D.107097;
      __comp_dtor  (D.107099);
    }
}

thoughts ?

Thanks!
Alex.

Reply via email to