Blame SOURCES/gdb-random-libstdcpp-prettyprinters-fail.patch

15e4b0
From: Pedro Alves <palves at redhat dot com>
15e4b0
To: gdb-patches at sourceware dot org
15e4b0
Subject: [PATCH] Fix GCC PR83906 - [8 Regression] Random FAIL: libstdc++-prettyprinters/80276.cc whatis p4
15e4b0
Date: Wed, 24 Jan 2018 17:27:22 +0000
15e4b0
Message-Id: <20180124172722.31553-1-palves@redhat.com>
15e4b0
15e4b0
GCC PR83906 [1] is about a GCC/libstdc++ GDB/Python type printer
15e4b0
testcase failing randomly, as shown by running (in libstdc++'s
15e4b0
testsuite):
15e4b0
15e4b0
 make check RUNTESTFLAGS=prettyprinters.exp=80276.cc
15e4b0
15e4b0
in a loop.  Sometimes you get this:
15e4b0
15e4b0
 FAIL: libstdc++-prettyprinters/80276.cc whatis p4
15e4b0
15e4b0
I.e., this:
15e4b0
 type = std::unique_ptr<std::vector<std::unique_ptr<std::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >>[]>>[99]>
15e4b0
15e4b0
instead of this:
15e4b0
 type = std::unique_ptr<std::vector<std::unique_ptr<std::list<std::string>[]>>[99]>
15e4b0
15e4b0
Jonathan Wakely tracked it on the printer side to this bit in
15e4b0
libstdc++'s type printer:
15e4b0
15e4b0
            if self.type_obj == type_obj:
15e4b0
                return strip_inline_namespaces(self.name)
15e4b0
15e4b0
This assumes the two types resolve to the same gdb.Type but some times
15e4b0
the comparison unexpectedly fails.
15e4b0
15e4b0
Running the testcase manually under Valgrind finds the problem in GDB:
15e4b0
15e4b0
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15e4b0
 ==6118== Conditional jump or move depends on uninitialised value(s)
15e4b0
 ==6118==    at 0x4C35CB0: bcmp (vg_replace_strmem.c:1100)
15e4b0
 ==6118==    by 0x6F773A: check_types_equal(type*, type*, VEC_type_equality_entry_d**) (gdbtypes.c:3515)
15e4b0
 ==6118==    by 0x6F7B00: check_types_worklist(VEC_type_equality_entry_d**, bcache*) (gdbtypes.c:3618)
15e4b0
 ==6118==    by 0x6F7C03: types_deeply_equal(type*, type*) (gdbtypes.c:3655)
15e4b0
 ==6118==    by 0x4D5B06: typy_richcompare(_object*, _object*, int) (py-type.c:1007)
15e4b0
 ==6118==    by 0x63D7E6C: PyObject_RichCompare (object.c:961)
15e4b0
 ==6118==    by 0x646EAEC: PyEval_EvalFrameEx (ceval.c:4960)
15e4b0
 ==6118==    by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
15e4b0
 ==6118==    by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
15e4b0
 ==6118==    by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
15e4b0
 ==6118==    by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
15e4b0
 ==6118==    by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
15e4b0
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15e4b0
15e4b0
That "bcmp" call is really a memcmp call in check_types_equal.  The
15e4b0
problem is that gdb is memcmp'ing two objects that are equal in value:
15e4b0
15e4b0
 (top-gdb) p *TYPE_RANGE_DATA (type1)
15e4b0
 $1 = {low = {kind = PROP_CONST, data = {const_val = 0, baton = 0x0}}, high = {kind = PROP_CONST, data = {const_val = 15, baton = 0xf}}, flag_upper_bound_is_count = 0,
15e4b0
   flag_bound_evaluated = 0}
15e4b0
 (top-gdb) p *TYPE_RANGE_DATA (type2)
15e4b0
 $2 = {low = {kind = PROP_CONST, data = {const_val = 0, baton = 0x0}}, high = {kind = PROP_CONST, data = {const_val = 15, baton = 0xf}}, flag_upper_bound_is_count = 0,
15e4b0
   flag_bound_evaluated = 0}
15e4b0
15e4b0
but differ in padding.  Notice the 4-byte hole:
15e4b0
15e4b0
  (top-gdb) ptype /o range_bounds
15e4b0
  /* offset    |  size */  type = struct range_bounds {
15e4b0
  /*    0      |    16 */    struct dynamic_prop {
15e4b0
  /*    0      |     4 */        dynamic_prop_kind kind;
15e4b0
  /* XXX  4-byte hole  */
15e4b0
  /*    8      |     8 */        union dynamic_prop_data {
15e4b0
  /*                 8 */            LONGEST const_val;
15e4b0
  /*                 8 */            void *baton;
15e4b0
15e4b0
				     /* total size (bytes):    8 */
15e4b0
				 } data;
15e4b0
15e4b0
which is filled with garbage:
15e4b0
15e4b0
  (top-gdb) x /40bx TYPE_RANGE_DATA (type1)
15e4b0
  0x2fa7ea0:      0x01    0x00    0x00    0x00    0x43    0x01    0x00    0x00
15e4b0
						  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15e4b0
  0x2fa7ea8:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
15e4b0
  0x2fa7eb0:      0x01    0x00    0x00    0x00    0xfe    0x7f    0x00    0x00
15e4b0
  0x2fa7eb8:      0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
15e4b0
  0x2fa7ec0:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
15e4b0
  (top-gdb) x /40bx TYPE_RANGE_DATA (type2)
15e4b0
  0x20379b0:      0x01    0x00    0x00    0x00    0xfe    0x7f    0x00    0x00
15e4b0
						  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15e4b0
  0x20379b8:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
15e4b0
  0x20379c0:      0x01    0x00    0x00    0x00    0xfe    0x7f    0x00    0x00
15e4b0
  0x20379c8:      0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
15e4b0
  0x20379d0:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
15e4b0
15e4b0
  (top-gdb) p memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2), sizeof (*TYPE_RANGE_DATA (type1)))
15e4b0
  $3 = -187
15e4b0
15e4b0
In some cases objects of type range_bounds are memset when allocated,
15e4b0
but then their dynamic_prop low/high fields are copied over from some
15e4b0
template dynamic_prop object that wasn't memset.  E.g.,
15e4b0
create_static_range_type's low/high locals are left with garbage in
15e4b0
the padding, and then that padding is copied over to the range_bounds
15e4b0
object's low/high fields.
15e4b0
15e4b0
At first, I considered making sure to always memset range_bounds
15e4b0
objects, thinking that maybe type objects are being put in some bcache
15e4b0
instance somewhere.  But then I hacked bcache/bcache_full to poison
15e4b0
non-pod types, and made dynamic_prop a non-pod, and GDB still
15e4b0
compiled.
15e4b0
15e4b0
So given that, it seems safest to not assume padding will always be
15e4b0
memset, and instead treat them as regular value types, implementing
15e4b0
(in)equality operators and using those instead of memcmp.
15e4b0
15e4b0
This fixes the random FAILs in GCC's testcase.
15e4b0
15e4b0
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83906
15e4b0
15e4b0
gdb/ChangeLog:
15e4b0
2018-01-24  Pedro Alves  <palves@redhat.com>
15e4b0
15e4b0
	GCC PR libstdc++/83906
15e4b0
	* gdbtypes.c (operator==(const dynamic_prop &,
15e4b0
	const dynamic_prop &)): New.
15e4b0
	(operator==(const range_bounds &, const range_bounds &)): New.
15e4b0
	(check_types_equal): Use them instead of memcmp.
15e4b0
	* gdbtypes.h (operator==(const dynamic_prop &,
15e4b0
	const dynamic_prop &)): Declare.
15e4b0
	(operator!=(const dynamic_prop &, const dynamic_prop &)): Declare.
15e4b0
	(operator==(const range_bounds &, const range_bounds &)): Declare.
15e4b0
	(operator!=(const range_bounds &, const range_bounds &)): Declare.
15e4b0
---
15e4b0
 gdb/gdbtypes.c | 41 +++++++++++++++++++++++++++++++++++++++--
15e4b0
 gdb/gdbtypes.h | 20 ++++++++++++++++++++
15e4b0
 2 files changed, 59 insertions(+), 2 deletions(-)
15e4b0
15e4b0
Index: gdb-8.0.1/gdb/gdbtypes.c
15e4b0
===================================================================
15e4b0
--- gdb-8.0.1.orig/gdb/gdbtypes.c
15e4b0
+++ gdb-8.0.1/gdb/gdbtypes.c
15e4b0
@@ -855,6 +855,44 @@ allocate_stub_method (struct type *type)
15e4b0
   return mtype;
15e4b0
 }
15e4b0
 
15e4b0
+/* See gdbtypes.h.  */
15e4b0
+
15e4b0
+bool
15e4b0
+operator== (const dynamic_prop &l, const dynamic_prop &r)
15e4b0
+{
15e4b0
+  if (l.kind != r.kind)
15e4b0
+    return false;
15e4b0
+
15e4b0
+  switch (l.kind)
15e4b0
+    {
15e4b0
+    case PROP_UNDEFINED:
15e4b0
+      return true;
15e4b0
+    case PROP_CONST:
15e4b0
+      return l.data.const_val == r.data.const_val;
15e4b0
+    case PROP_ADDR_OFFSET:
15e4b0
+    case PROP_LOCEXPR:
15e4b0
+    case PROP_LOCLIST:
15e4b0
+      return l.data.baton == r.data.baton;
15e4b0
+    }
15e4b0
+
15e4b0
+  gdb_assert_not_reached ("unhandled dynamic_prop kind");
15e4b0
+}
15e4b0
+
15e4b0
+/* See gdbtypes.h.  */
15e4b0
+
15e4b0
+bool
15e4b0
+operator== (const range_bounds &l, const range_bounds &r)
15e4b0
+{
15e4b0
+#define FIELD_EQ(FIELD) (l.FIELD == r.FIELD)
15e4b0
+
15e4b0
+  return (FIELD_EQ (low)
15e4b0
+	  && FIELD_EQ (high)
15e4b0
+	  && FIELD_EQ (flag_upper_bound_is_count)
15e4b0
+	  && FIELD_EQ (flag_bound_evaluated));
15e4b0
+
15e4b0
+#undef FIELD_EQ
15e4b0
+}
15e4b0
+
15e4b0
 /* Create a range type with a dynamic range from LOW_BOUND to
15e4b0
    HIGH_BOUND, inclusive.  See create_range_type for further details. */
15e4b0
 
15e4b0
@@ -3466,8 +3504,7 @@ check_types_equal (struct type *type1, s
15e4b0
 
15e4b0
   if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
15e4b0
     {
15e4b0
-      if (memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2),
15e4b0
-		  sizeof (*TYPE_RANGE_DATA (type1))) != 0)
15e4b0
+      if (*TYPE_RANGE_DATA (type1) != *TYPE_RANGE_DATA (type2))
15e4b0
 	return 0;
15e4b0
     }
15e4b0
   else
15e4b0
Index: gdb-8.0.1/gdb/gdbtypes.h
15e4b0
===================================================================
15e4b0
--- gdb-8.0.1.orig/gdb/gdbtypes.h
15e4b0
+++ gdb-8.0.1/gdb/gdbtypes.h
15e4b0
@@ -408,6 +408,16 @@ struct dynamic_prop
15e4b0
   union dynamic_prop_data data;
15e4b0
 };
15e4b0
 
15e4b0
+/* Compare two dynamic_prop objects for equality.  dynamic_prop
15e4b0
+   instances are equal iff they have the same type and storage.  */
15e4b0
+extern bool operator== (const dynamic_prop &l, const dynamic_prop &r);
15e4b0
+
15e4b0
+/* Compare two dynamic_prop objects for inequality.  */
15e4b0
+static inline bool operator!= (const dynamic_prop &l, const dynamic_prop &r)
15e4b0
+{
15e4b0
+  return !(l == r);
15e4b0
+}
15e4b0
+
15e4b0
 /* * Define a type's dynamic property node kind.  */
15e4b0
 enum dynamic_prop_node_kind
15e4b0
 {
15e4b0
@@ -568,6 +578,16 @@ struct range_bounds
15e4b0
   int flag_bound_evaluated : 1;
15e4b0
 };
15e4b0
 
15e4b0
+/* Compare two range_bounds objects for equality.  Simply does
15e4b0
+   memberwise comparison.  */
15e4b0
+extern bool operator== (const range_bounds &l, const range_bounds &r);
15e4b0
+
15e4b0
+/* Compare two range_bounds objects for inequality.  */
15e4b0
+static inline bool operator!= (const range_bounds &l, const range_bounds &r)
15e4b0
+{
15e4b0
+  return !(l == r);
15e4b0
+}
15e4b0
+
15e4b0
 union type_specific
15e4b0
 {
15e4b0
   /* * CPLUS_STUFF is for TYPE_CODE_STRUCT.  It is initialized to