@@ -72,6 +72,12 @@ AC_ARG_ENABLE(debug-self-comparison,
ENABLE_DEBUG_SELF_COMPARISON=$enableval,
ENABLE_DEBUG_SELF_COMPARISON=no)
+AC_ARG_ENABLE(debug-equality-hash-consistency,
+ AS_HELP_STRING([--enable-debug-equality-hash-consistency=yes|no],
+ [enable debugging of equality / hash value consistency in unordered maps (default is no)]),
+ ENABLE_DEBUG_EQUALITY_HASH_CONSISTENCY=$enableval,
+ ENABLE_DEBUG_EQUALITY_HASH_CONSISTENCY=no)
+
AC_ARG_ENABLE(deb,
AS_HELP_STRING([--enable-deb=yes|no|auto],
[enable the support of deb in abipkgdiff (default is auto)]),
@@ -313,6 +319,16 @@ fi
AM_CONDITIONAL(ENABLE_DEBUG_SELF_COMPARISON, test x$ENABLE_DEBUG_SELF_COMPARISON = xyes)
+dnl enable the debugging of equality / hash value consistency in the abidw XML writer
+if test x$ENABLE_DEBUG_EQUALITY_HASH_CONSISTENCY = xyes; then
+ AC_DEFINE([WITH_DEBUG_EQUALITY_HASH_CONSISTENCY], 1, [compile equality / hash value consistency checks])
+ AC_MSG_NOTICE([support of debugging equality / hash value consistency is enabled])
+else
+ AC_MSG_NOTICE([support of debugging equality / hash value consistency is disabled])
+fi
+
+AM_CONDITIONAL(ENABLE_DEBUG_EQUALITY_HASH_CONSISTENCY, test x$ENABLE_DEBUG_EQUALITY_HASH_CONSISTENCY = xyes)
+
dnl Check for the dpkg program
if test x$ENABLE_DEB = xauto -o x$ENABLE_DEB = xyes; then
AC_CHECK_PROG(HAS_DPKG, dpkg, yes, no)
@@ -115,6 +115,41 @@ struct type_hasher
{return hash_type(t);}
}; // end struct type_hasher
+template <typename T>
+static void check_set_equality_hash_consistency(
+ const T& haystack, const typename T::key_type& needle)
+{
+#ifdef WITH_DEBUG_EQUALITY_HASH_CONSISTENCY
+ abigail::diff_utils::deep_ptr_eq_functor eq;
+ type_hasher hasher;
+ const auto needle_hash = hasher(needle);
+ for (const auto& key : haystack)
+ ABG_ASSERT(!eq(needle, key) || needle_hash == hasher(key));
+#else
+ (void) haystack;
+ (void) needle;
+#endif
+}
+
+template <typename T>
+static void check_map_equality_hash_consistency(
+ const T& haystack, const typename T::key_type& needle)
+{
+#ifdef WITH_DEBUG_EQUALITY_HASH_CONSISTENCY
+ abigail::diff_utils::deep_ptr_eq_functor eq;
+ type_hasher hasher;
+ const auto needle_hash = hasher(needle);
+ for (const auto& key_value : haystack)
+ {
+ const auto& key = key_value.first;
+ ABG_ASSERT(!eq(key, needle) || needle_hash == hasher(key));
+ }
+#else
+ (void) haystack;
+ (void) needle;
+#endif
+}
+
/// A convenience typedef for a map that associates a pointer to type
/// to a string. The pointer to type is hashed as fast as possible.
typedef unordered_map<type_base*,
@@ -421,6 +456,7 @@ public:
if (c == 0)
c = const_cast<type_base*>(t);
+ check_map_equality_hash_consistency(m_type_id_map, c);
auto insertion = m_type_id_map.emplace(c, interned_string());
interned_string& id = insertion.first->second;
@@ -544,14 +580,25 @@ public:
{
// If the type is a function type, record it in a dedicated data
// structure.
- if (function_type* f = is_function_type(t.get()))
- m_referenced_fn_types_set.insert(f);
- else if (!t->get_naked_canonical_type())
- // If the type doesn't have a canonical type, record it in a
- // dedicated data structure.
- m_referenced_non_canonical_types_set.insert(t.get());
+ type_base* t_ptr = t.get();
+ if (function_type* f = is_function_type(t_ptr))
+ {
+ check_set_equality_hash_consistency(m_referenced_fn_types_set, f);
+ m_referenced_fn_types_set.insert(f);
+ }
+ else if (!t_ptr->get_naked_canonical_type())
+ {
+ // If the type doesn't have a canonical type, record it in a
+ // dedicated data structure.
+ check_set_equality_hash_consistency(
+ m_referenced_non_canonical_types_set, t_ptr);
+ m_referenced_non_canonical_types_set.insert(t_ptr);
+ }
else
- m_referenced_types_set.insert(t.get());
+ {
+ check_set_equality_hash_consistency(m_referenced_types_set, t_ptr);
+ m_referenced_types_set.insert(t_ptr);
+ }
}
/// Test if a given type has been referenced by a pointer, a
@@ -564,15 +611,26 @@ public:
bool
type_is_referenced(const type_base_sptr& t)
{
- if (function_type *f = is_function_type(t.get()))
- return (m_referenced_fn_types_set.find(f)
- != m_referenced_fn_types_set.end());
- else if (!t->get_naked_canonical_type())
- return (m_referenced_non_canonical_types_set.find(t.get())
- != m_referenced_non_canonical_types_set.end());
+ type_base* t_ptr = t.get();
+ if (function_type *f = is_function_type(t_ptr))
+ {
+ check_set_equality_hash_consistency(m_referenced_fn_types_set, f);
+ return (m_referenced_fn_types_set.find(f)
+ != m_referenced_fn_types_set.end());
+ }
+ else if (!t_ptr->get_naked_canonical_type())
+ {
+ check_set_equality_hash_consistency(
+ m_referenced_non_canonical_types_set, t_ptr);
+ return (m_referenced_non_canonical_types_set.find(t_ptr)
+ != m_referenced_non_canonical_types_set.end());
+ }
else
- return m_referenced_types_set.find
- (t.get()) != m_referenced_types_set.end();
+ {
+ check_set_equality_hash_consistency(m_referenced_types_set, t_ptr);
+ return (m_referenced_types_set.find(t_ptr)
+ != m_referenced_types_set.end());
+ }
}
/// A comparison functor to compare pointers to @ref type_base.
@@ -727,6 +785,7 @@ public:
type_base *c = t->get_naked_canonical_type();
if (c == 0)
c = const_cast<type_base*>(t);
+ check_set_equality_hash_consistency(m_emitted_type_set, c);
m_emitted_type_set.insert(c);
}
@@ -739,6 +798,7 @@ public:
bool
type_is_emitted(const type_base *t) const
{
+ check_set_equality_hash_consistency(m_emitted_type_set, t);
return m_emitted_type_set.find(t) != m_emitted_type_set.end();
}
@@ -792,6 +852,7 @@ public:
{
class_or_union* cl = is_class_or_union_type(t);
ABG_ASSERT(cl && cl->get_is_declaration_only());
+ check_set_equality_hash_consistency(m_emitted_decl_only_set, t);
m_emitted_decl_only_set.insert(t);
}
@@ -814,10 +875,8 @@ public:
bool
decl_only_type_is_emitted(const type_base* t) const
{
- type_ptr_set_type::const_iterator i = m_emitted_decl_only_set.find(t);
- if (i == m_emitted_decl_only_set.end())
- return false;
- return true;
+ check_set_equality_hash_consistency(m_emitted_decl_only_set, t);
+ return m_emitted_decl_only_set.find(t) != m_emitted_decl_only_set.end();
}
/// Test if a declaration-only class has been emitted.
@@ -2273,7 +2332,10 @@ record_unemitted_type(type_ptr_set_type& types,
== tu.get_absolute_path())
&& !ctxt.type_is_emitted(t)
&& !ctxt.decl_only_type_is_emitted(t))
- types.insert(t);
+ {
+ check_set_equality_hash_consistency(types, t);
+ types.insert(t);
+ }
}
/// Serialize a translation unit to an output stream.