Bug 87847 - spec_hasher::hash does not match with spec_hasher::equal
Summary: spec_hasher::hash does not match with spec_hasher::equal
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 11.0
Assignee: Jason Merrill
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-11-01 12:05 UTC by Martin Liška
Modified: 2022-01-07 09:16 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-06-05 00:00:00


Attachments
patch to trigger the problem (552 bytes, patch)
2018-11-01 12:05 UTC, Martin Liška
Details | Diff
patch to ignore type_canonical for TTP (399 bytes, patch)
2019-05-20 17:42 UTC, Jason Merrill
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Liška 2018-11-01 12:05:52 UTC
Created attachment 44941 [details]
patch to trigger the problem

As mentioned in following sub-thread: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg01885.html

There's violation of hash table in type_specializations hash table.
Attached patch exposes that.

$ ./xg++ -B. /home/marxin/Programming/gcc/gcc/testsuite/g++.dg/template/ttp23.C -c
/home/marxin/Programming/gcc/gcc/testsuite/g++.dg/template/ttp23.C: In instantiation of ‘struct B<A>’:
/home/marxin/Programming/gcc/gcc/testsuite/g++.dg/template/ttp23.C:15:8:   required from here
/home/marxin/Programming/gcc/gcc/testsuite/g++.dg/template/ttp23.C:8:17: internal compiler error: in equal, at cp/pt.c:1699
    8 |     friend bool foo (const B<Q>& a);
      |                 ^~~
0x9c1b40 spec_hasher::equal(spec_entry*, spec_entry*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:1698
0xa48639 hash_table<spec_hasher, xcallocator>::find_with_hash(spec_entry* const&, unsigned int)
	/home/marxin/Programming/gcc/gcc/hash-table.h:863
0x9e51f7 lookup_template_class_1
	/home/marxin/Programming/gcc/gcc/cp/pt.c:9353
0x9e785d lookup_template_class(tree_node*, tree_node*, tree_node*, tree_node*, int, int)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:9680
0x9f46a4 tsubst_aggr_type
	/home/marxin/Programming/gcc/gcc/cp/pt.c:12685
0x9ff5ac tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:14333
0x9ff527 tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:14324
0x9fdb8b tsubst_arg_types
	/home/marxin/Programming/gcc/gcc/cp/pt.c:13930
0x9fe22e tsubst_function_type
	/home/marxin/Programming/gcc/gcc/cp/pt.c:14071
0xa018c3 tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:14808
0x9f5dd1 tsubst_function_decl
	/home/marxin/Programming/gcc/gcc/cp/pt.c:12949
0x9f927f tsubst_template_decl
	/home/marxin/Programming/gcc/gcc/cp/pt.c:13253
0x9fa86b tsubst_decl
	/home/marxin/Programming/gcc/gcc/cp/pt.c:13355
0x9febb7 tsubst(tree_node*, tree_node*, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:14251
0x9e9f42 tsubst_friend_function
	/home/marxin/Programming/gcc/gcc/cp/pt.c:10316
0x9ef597 instantiate_class_template_1
	/home/marxin/Programming/gcc/gcc/cp/pt.c:11365
0x9ef816 instantiate_class_template(tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:11430
0xa90c52 complete_type(tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/typeck.c:138
0x8ea857 start_decl_1(tree_node*, bool)
	/home/marxin/Programming/gcc/gcc/cp/decl.c:5278
0x91285f start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
	/home/marxin/Programming/gcc/gcc/cp/decl.c:5241
Comment 1 Martin Liška 2019-05-07 12:17:12 UTC
May I please ping this? I would like to finish the hast table sanitization patch in this stage1.
Comment 2 Marek Polacek 2019-05-07 21:58:27 UTC
In the ttp23.C testcase we're comparing B<Q> and B<Q>.  In one case the template argument is

 <tree_vec 0x7fffeab33920 length:1
    elt:0 <template_template_parm 0x7fffeab3ad20 VOID
        align:8 warn_if_not_align:0 symtab:0 alias-set -1 structural-equality
       index 0 level 1 orig_level 2
        chain <template_decl 0x7fffea9f8b80 Q>>>

and the other is

 <tree_vec 0x7fffeab33560 length:1
    elt:0 <template_template_parm 0x7fffeab3a348 VOID
        align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7fffeab25c78
       index 0 level 1 orig_level 1
        chain <template_decl 0x7fffea9f8680 Q>>>

same_type_p says they're same, so comp_template_args returns true.  One of the template_template_parms has TYPE_CANONICAL, so we hash it as:

 1905       if (TYPE_CANONICAL (arg))
 1906         return iterative_hash_object (TYPE_HASH (TYPE_CANONICAL (arg)),
 1907                                       val);

but the other type doesn't have a canonical type:

 1910       /* Otherwise just compare the types during lookup.  */
 1911       return val;

so the hashes end up being different.
Comment 3 Marek Polacek 2019-05-09 00:31:05 UTC
An idea would be to hash TEMPLATE_TEMPLATE_PARMs differently in iterative_hash_template_arg: hash its TEMPLATE_TYPE_PARM_INDEX and TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL, so that when they compare equal, they hash equal.
Comment 4 Marek Polacek 2019-05-09 19:36:26 UTC
Or maybe just

@@ -1879,6 +1888,9 @@ iterative_hash_template_arg (tree arg, hashval_t val)
    return val;
       }
 
+    case TEMPLATE_TEMPLATE_PARM:
+      return val;
+
     default:
       break;
     }
Comment 5 Martin Liška 2019-05-10 06:55:35 UTC
(In reply to Marek Polacek from comment #4)
> Or maybe just
> 
> @@ -1879,6 +1888,9 @@ iterative_hash_template_arg (tree arg, hashval_t val)
>     return val;
>        }
>  
> +    case TEMPLATE_TEMPLATE_PARM:
> +      return val;
> +
>      default:
>        break;
>      }

Thank you Marek for working on that. If I apply both my and your patches I've got:

$ cat ba.ii
template < typename > struct A;
 template < typename > class B { public:   typedef int value_type;   typedef int pointer;   typedef int reference;   typedef int const_reference;   typedef long size_type;   typedef long difference_type;   typedef int iterator; };
 template < typename _Tp > class _Bitmap_counter {   typedef B< A< _Tp > > _BPVector;   typedef typename _BPVector::size_type _Index_type;   typedef _Tp pointer;  public:   _Bitmap_counter(_BPVector); };
 B< long > a;
 template < typename > class bitmap_allocator {   typedef long size_type;   typedef long difference_type;   typedef int pointer;   struct _Alloc_block;   typedef A< _Alloc_block * > _Block_pair;   typedef B< _Block_pair > _BPVector;   static _BPVector b;   static _Bitmap_counter< _Alloc_block * > d; };
 template < typename _Tp > _Bitmap_counter< typename bitmap_allocator< _Tp >::_Alloc_block * >     bitmap_allocator< _Tp >::d(b);
 template class B<     A< bitmap_allocator< wchar_t >::_Alloc_block * > >;
 template class bitmap_allocator< char >;

$ /home/marxin/Programming/gcc2/objdir/./gcc/xgcc -B/home/marxin/Programming/gcc2/objdir/./gcc ba.ii
ba.ii: In instantiation of ‘_Bitmap_counter<bitmap_allocator<char>::_Alloc_block*> bitmap_allocator<char>::d’:
ba.ii:8:17:   required from here
ba.ii:6:127: internal compiler error: in instantiate_decl, at cp/pt.c:24494
    6 |  template < typename _Tp > _Bitmap_counter< typename bitmap_allocator< _Tp >::_Alloc_block * >     bitmap_allocator< _Tp >::d(b);
      |                                                                                                                               ^
0x9a3dea instantiate_decl(tree_node*, bool, bool)
	../../gcc/cp/pt.c:24493
0x8e1cf3 mark_used(tree_node*, int)
	../../gcc/cp/decl2.c:5561
0x9aca07 tsubst_copy
	../../gcc/cp/pt.c:15714
0x997e37 tsubst_copy
	../../gcc/cp/pt.c:15534
0x997e37 tsubst_copy_and_build(tree_node*, tree_node*, int, tree_node*, bool, bool)
	../../gcc/cp/pt.c:19483
0x999f64 tsubst_copy_and_build(tree_node*, tree_node*, int, tree_node*, bool, bool)
	../../gcc/cp/pt.c:19606
0x99ae44 tsubst_copy_and_build(tree_node*, tree_node*, int, tree_node*, bool, bool)
	../../gcc/cp/pt.c:19244
0x9a7348 tsubst_copy_and_build(tree_node*, tree_node*, int, tree_node*, bool, bool)
	../../gcc/cp/pt.c:18248
0x9a7348 tsubst_expr(tree_node*, tree_node*, int, tree_node*, bool)
	../../gcc/cp/pt.c:17924
0x9aaae4 tsubst_expr(tree_node*, tree_node*, int, tree_node*, bool)
	../../gcc/cp/pt.c:17015
0x9aaae4 tsubst_init
	../../gcc/cp/pt.c:15493
0x9a27d1 regenerate_decl_from_template
	../../gcc/cp/pt.c:24163
0x9a27d1 instantiate_decl(tree_node*, bool, bool)
	../../gcc/cp/pt.c:24707
0x9bc031 do_type_instantiation(tree_node*, tree_node*, int)
	../../gcc/cp/pt.c:24024
0x975f37 cp_parser_explicit_instantiation
	../../gcc/cp/parser.c:17206
0x9785b1 cp_parser_declaration
	../../gcc/cp/parser.c:13190
0x978c9f cp_parser_translation_unit
	../../gcc/cp/parser.c:4701
0x978c9f c_parse_file()
	../../gcc/cp/parser.c:41181
0xa82ce0 c_common_parse_file()
	../../gcc/c-family/c-opts.c:1156

$ g++-8 ba.ii -c
[OK]
Comment 6 Jason Merrill 2019-05-20 17:42:07 UTC
Created attachment 46387 [details]
patch to ignore type_canonical for TTP

Does this work better?
Comment 7 Martin Liška 2019-06-06 08:54:18 UTC
Apparently, this is not an issue any longer.
Comment 8 Martin Liška 2019-06-10 11:24:02 UTC
So the issue is still present:
https://gcc.gnu.org/ml/gcc-regression/2019-06/msg00144.html

I'm testing:
https://gcc.gnu.org/bugzilla/attachment.cgi?id=46387&action=diff right now
Comment 9 Martin Liška 2019-06-10 12:23:33 UTC
(In reply to Martin Liška from comment #8)
> So the issue is still present:
> https://gcc.gnu.org/ml/gcc-regression/2019-06/msg00144.html
> 
> I'm testing:
> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46387&action=diff right now

So with patch I still see couple of ICEs remaining:

FAIL: g++.dg/cpp0x/udlit-template.C  -std=c++14 (internal compiler error)
FAIL: g++.dg/cpp0x/udlit-template.C  -std=c++14 (test for excess errors)
FAIL: g++.dg/cpp0x/udlit-template.C  -std=c++17 (internal compiler error)
FAIL: g++.dg/cpp0x/udlit-template.C  -std=c++17 (test for excess errors)
FAIL: g++.dg/cpp0x/variadic98.C  -std=c++17 (internal compiler error)
FAIL: g++.dg/cpp0x/variadic98.C  -std=c++17 (test for excess errors)
FAIL: g++.dg/cpp1y/feat-cxx14.C   (test for excess errors)
FAIL: g++.dg/cpp1z/feat-cxx1z.C  -std=gnu++17 (test for excess errors)
FAIL: g++.dg/cpp1z/pr85569.C  -std=c++17 (test for excess errors)
FAIL: g++.dg/cpp2a/feat-cxx2a.C   (test for excess errors)
FAIL: g++.dg/tm/pr46646.C  -std=gnu++14 (internal compiler error)
FAIL: g++.dg/tm/pr46646.C  -std=gnu++14 (test for excess errors)

One reduced test-case:

$ cat 1.ii
template <char...> int operator"" _abc();
template <> int operator"" _abc();

$ ./xg++ -B. 1.ii -c
hash table checking failed: equal operator returns true for a pair of values with a different hash value
1.ii:2:33: internal compiler error: in hashtab_chk_error, at hash-table.h:1022
    2 | template <> int operator"" _abc();
      |                                 ^
0xaf623e hashtab_chk_error
	/home/marxin/Programming/gcc/gcc/hash-table.h:1022
0xb83ef9 hash_table<spec_hasher, false, xcallocator>::find_slot_with_hash(spec_entry* const&, unsigned int, insert_option)
	/home/marxin/Programming/gcc/gcc/hash-table.h:963
0xafe5d8 register_specialization
	/home/marxin/Programming/gcc/gcc/cp/pt.c:1566
0xb05860 check_explicit_specialization(tree_node*, tree_node*, int, int, tree_node*)
	/home/marxin/Programming/gcc/gcc/cp/pt.c:3237
0x9aa99d grokfndecl
	/home/marxin/Programming/gcc/gcc/cp/decl.c:9218
0x9b6999 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, decl_context, int, tree_node**)
	/home/marxin/Programming/gcc/gcc/cp/decl.c:12803
0x9993f2 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
	/home/marxin/Programming/gcc/gcc/cp/decl.c:5062
0xab7026 cp_parser_init_declarator
	/home/marxin/Programming/gcc/gcc/cp/parser.c:20357
0xac6cab cp_parser_single_declaration
	/home/marxin/Programming/gcc/gcc/cp/parser.c:28244
0xab0ff7 cp_parser_explicit_specialization
	/home/marxin/Programming/gcc/gcc/cp/parser.c:17304
0xaa9bc8 cp_parser_declaration
	/home/marxin/Programming/gcc/gcc/cp/parser.c:13168
0xaa9ef4 cp_parser_toplevel_declaration
	/home/marxin/Programming/gcc/gcc/cp/parser.c:13251
0xa9719a cp_parser_translation_unit
	/home/marxin/Programming/gcc/gcc/cp/parser.c:4690
0xaee97d c_parse_file()
	/home/marxin/Programming/gcc/gcc/cp/parser.c:41176
0xcb3987 c_common_parse_file()
	/home/marxin/Programming/gcc/gcc/c-family/c-opts.c:1156

I'm planning to disable the sanitization of the 2 hash tables now.

@Jason: can you please take a look at the remaining test-cases?
Comment 10 Martin Liška 2019-06-11 07:55:50 UTC
Author: marxin
Date: Tue Jun 11 07:55:19 2019
New Revision: 272144

URL: https://gcc.gnu.org/viewcvs?rev=272144&root=gcc&view=rev
Log:
Disable htable sanitization in pt.c (PR c++/87847).

2019-06-11  Martin Liska  <mliska@suse.cz>

	PR c++/87847
	* hash-table.h: Extend create_gcc, add one parameter
	that is passed into hash_table::hash_table.
2019-06-11  Martin Liska  <mliska@suse.cz>

	PR c++/87847
	* pt.c (init_template_processing): Disable hash table
	sanitization for decl_specializations and type_specializations.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c
    trunk/gcc/hash-table.h
Comment 11 Patrick Palka 2020-05-12 16:48:12 UTC
I posted a patch to enable sanitization for the spec_hasher tables for GCC 11 here: https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545525.html

With current trunk I wasn't able to reproduce any sanitization errors in the testsuite or in other libraries even with a debugging patch similar to Martin's (on x86_64-pc-linux-gnu).  I suspect they have been fixed by the patches for PR94454.
Comment 12 Martin Liška 2020-05-13 13:54:55 UTC
(In reply to Patrick Palka from comment #11)
> I posted a patch to enable sanitization for the spec_hasher tables for GCC
> 11 here: https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545525.html
> 
> With current trunk I wasn't able to reproduce any sanitization errors in the
> testsuite or in other libraries even with a debugging patch similar to
> Martin's (on x86_64-pc-linux-gnu).  I suspect they have been fixed by the
> patches for PR94454.

Cool! Thank you Patrick for working on that.
Comment 13 GCC Commits 2020-05-19 03:52:40 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:573e5f0500968dcf4025b8fc0ae5fb367f9c70d9

commit r11-477-g573e5f0500968dcf4025b8fc0ae5fb367f9c70d9
Author: Patrick Palka <ppalka@redhat.com>
Date:   Mon May 18 23:50:32 2020 -0400

    c++: Enable spec_hasher table sanitization [PR87847]
    
    It looks like hash table sanitization is now safe to enable for the
    decl_specializations and type_specializations tables, probably ever
    since PR94454 was fixed.
    
    gcc/cp/ChangeLog:
    
            PR c++/87847
            * pt.c (init_template_processing): Enable sanitization for
            decl_specializations and type_specializations.
Comment 14 Patrick Palka 2020-05-26 14:16:06 UTC
Fixed for GCC 11.