https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70683
Bug ID: 70683 Summary: [6 Regression] -fcompare-debug bug with -fsanitize=address Product: gcc Version: 6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: jakub at gcc dot gnu.org CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org Target Milestone: --- On a testcase that has been provided privately to me and I can't share (and that can't be easily reduced), I'm seeing differences in sanopt optimization, without -gtoggle ASAN_CHECK is optimized away, while with -gtoggle it is. maybe_optimize_asan_check_ifn works with a hash_map using tree_operand_hash. What I'm seeing is that in both cases we first process ASAN_CHECK with ptr &m_nullId.m_id which is ADDR_EXPR of COMPONENT_REF of VAR_DECL, and then later on there is ASAN_CHECK with ptr &m_nullId.m_id which is actually ADDR_EXPR of COMPONENT_REF of MEM_REF of ADDR_EXPR of VAR_DECL. The FIELD_DECL and VAR_DECL in both cases are the same. Now, because of the VAR_DECL vs. MEM_REF[&VAR_DECL, 0] difference both hash differently using iterative_hash_expr. Unlike the hash, the comparison is done using operand_equal_p (, , 0), which has: 2833 else if (flags & OEP_ADDRESS_OF) 2834 { 2835 /* If we are interested in comparing addresses ignore 2836 MEM_REF wrappings of the base that can appear just for 2837 TBAA reasons. */ 2838 if (TREE_CODE (arg0) == MEM_REF 2839 && DECL_P (arg1) 2840 && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR 2841 && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1 2842 && integer_zerop (TREE_OPERAND (arg0, 1))) 2843 return 1; 2844 else if (TREE_CODE (arg1) == MEM_REF 2845 && DECL_P (arg0) 2846 && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR 2847 && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0 2848 && integer_zerop (TREE_OPERAND (arg1, 1))) 2849 return 1; 2850 return 0; 2851 } and thus returns that the two are equal. While both of the decls in here (VAR_DECL and FIELD_DECL) have the same DECL_UID for no -gtoggle vs. -gtoggle, I presume the problem is that there are other tree expressions pushed into the hash_map as keys that have some DECL_UID differences somewhere, in any case both the hash maps have the same number of elements, but report different number of collisions (note debug stmts never query anything, so that is not the issue). So, I believe the bug is that we have a hash function that can return different hashes even for objects that compare equal by the comparison function, so it is then by pure luck if we find a match or not. IMHO the right solution would be to have next to operand_equal_p a hashing function that guarantees that if operand_equal_p returns true on two tree expressions, then they have the same hash. As short term, perhaps (maybe just for sanopt, as that is where the problem is reported), we could use a comparison function that compares both the hash values and operand_equal_p, i.e. tree expressions that hash differently would never compare equal. This can be done either by remembering also the hash value, or just computing iterative_hash_expr each time.