This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH] Fix GCC PR83906 - [8 Regression] Random FAIL: libstdc++-prettyprinters/80276.cc whatis p4
- From: Simon Marchi <simon dot marchi at ericsson dot com>
- To: Pedro Alves <palves at redhat dot com>, <gdb-patches at sourceware dot org>
- Date: Wed, 24 Jan 2018 13:24:45 -0500
- Subject: Re: [PATCH] Fix GCC PR83906 - [8 Regression] Random FAIL: libstdc++-prettyprinters/80276.cc whatis p4
- Authentication-results: sourceware.org; auth=none
- Authentication-results: spf=none (sender IP is ) smtp.mailfrom=simon dot marchi at ericsson dot com;
- References: <20180124172722.31553-1-palves@redhat.com>
- Spamdiagnosticmetadata: NSPM
- Spamdiagnosticoutput: 1:99
On 2018-01-24 12:27 PM, Pedro Alves wrote:
> GCC PR83906 [1] is about a GCC/libstdc++ GDB/Python type printer
> testcase failing randomly, as shown by running (in libstdc++'s
> testsuite):
>
> make check RUNTESTFLAGS=prettyprinters.exp=80276.cc
>
> in a loop. Sometimes you get this:
>
> FAIL: libstdc++-prettyprinters/80276.cc whatis p4
>
> I.e., this:
> type = std::unique_ptr<std::vector<std::unique_ptr<std::list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >>[]>>[99]>
>
> instead of this:
> type = std::unique_ptr<std::vector<std::unique_ptr<std::list<std::string>[]>>[99]>
>
> Jonathan Wakely tracked it on the printer side to this bit in
> libstdc++'s type printer:
>
> if self.type_obj == type_obj:
> return strip_inline_namespaces(self.name)
>
> This assumes the two types resolve to the same gdb.Type but some times
> the comparison unexpectedly fails.
>
> Running the testcase manually under Valgrind finds the problem in GDB:
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ==6118== Conditional jump or move depends on uninitialised value(s)
> ==6118== at 0x4C35CB0: bcmp (vg_replace_strmem.c:1100)
> ==6118== by 0x6F773A: check_types_equal(type*, type*, VEC_type_equality_entry_d**) (gdbtypes.c:3515)
> ==6118== by 0x6F7B00: check_types_worklist(VEC_type_equality_entry_d**, bcache*) (gdbtypes.c:3618)
> ==6118== by 0x6F7C03: types_deeply_equal(type*, type*) (gdbtypes.c:3655)
> ==6118== by 0x4D5B06: typy_richcompare(_object*, _object*, int) (py-type.c:1007)
> ==6118== by 0x63D7E6C: PyObject_RichCompare (object.c:961)
> ==6118== by 0x646EAEC: PyEval_EvalFrameEx (ceval.c:4960)
> ==6118== by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
> ==6118== by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
> ==6118== by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
> ==6118== by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
> ==6118== by 0x646DC08: PyEval_EvalFrameEx (ceval.c:4519)
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> That "bcmp" call is really a memcmp call in check_types_equal. The
> problem is that gdb is memcmp'ing two objects that are equal in value:
>
> (top-gdb) p *TYPE_RANGE_DATA (type1)
> $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,
> flag_bound_evaluated = 0}
> (top-gdb) p *TYPE_RANGE_DATA (type2)
> $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,
> flag_bound_evaluated = 0}
>
> but differ in padding. Notice the 4-byte hole:
>
> (top-gdb) ptype /o range_bounds
> /* offset | size */ type = struct range_bounds {
> /* 0 | 16 */ struct dynamic_prop {
> /* 0 | 4 */ dynamic_prop_kind kind;
> /* XXX 4-byte hole */
> /* 8 | 8 */ union dynamic_prop_data {
> /* 8 */ LONGEST const_val;
> /* 8 */ void *baton;
>
> /* total size (bytes): 8 */
> } data;
>
> which is filled with garbage:
>
> (top-gdb) x /40bx TYPE_RANGE_DATA (type1)
> 0x2fa7ea0: 0x01 0x00 0x00 0x00 0x43 0x01 0x00 0x00
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 0x2fa7ea8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> 0x2fa7eb0: 0x01 0x00 0x00 0x00 0xfe 0x7f 0x00 0x00
> 0x2fa7eb8: 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> 0x2fa7ec0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> (top-gdb) x /40bx TYPE_RANGE_DATA (type2)
> 0x20379b0: 0x01 0x00 0x00 0x00 0xfe 0x7f 0x00 0x00
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 0x20379b8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> 0x20379c0: 0x01 0x00 0x00 0x00 0xfe 0x7f 0x00 0x00
> 0x20379c8: 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> 0x20379d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
>
> (top-gdb) p memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2), sizeof (*TYPE_RANGE_DATA (type1)))
> $3 = -187
>
> In some cases objects of type range_bounds are memset when allocated,
> but then their dynamic_prop low/high fields are copied over from some
> template dynamic_prop object that wasn't memset. E.g.,
> create_static_range_type's low/high locals are left with garbage in
> the padding, and then that padding is copied over to the range_bounds
> object's low/high fields.
>
> At first, I considered making sure to always memset range_bounds
> objects, thinking that maybe type objects are being put in some bcache
> instance somewhere. But then I hacked bcache/bcache_full to poison
> non-pod types, and made dynamic_prop a non-pod, and GDB still
> compiled.
>
> So given that, it seems safest to not assume padding will always be
> memset, and instead treat them as regular value types, implementing
> (in)equality operators and using those instead of memcmp.
>
> This fixes the random FAILs in GCC's testcase.
>
> [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83906
LGTM.
Simon