[05/13] suppression: Support offset_of_{first,last}_data_member_regexp offset selectors

Message ID 87bklbq8sh.fsf_-_@redhat.com
State New
Headers
Series Support negative suppression specifications |

Commit Message

Dodji Seketeli March 2, 2023, 6:59 p.m. UTC
  Hello,

This patch adds support for two data member offset selector
expressions for properties of the [suppress_type] directive:

offset_of_first_data_member_regexp() and offset_of_last_data_member_regexp().

These function-call expressions take a regular expression argument and
evaluate to the offset of the first (resp. last) data member matching
the regular expression argument.

An example of their use would be be:

    [suppress_type]
      type_kind = struct
      has_data_member_inserted_between =
	{
	  offset_of_first_data_member_regexp(^__special_padding_space),
	  offset_of_last_data_member_regexp(^__special_padding_space)
	}

This would be useful to suppress change reports involving a struct
which has "padding" data members added on-purpose like:

    struct S
    {
      int member0;
      char member1;
      unsigned __special_padding_space1;
      unsigned __special_padding_space2;
      unsigned __special_padding_space3;
    };

	* doc/manuals/libabigail-concepts.rst: Document the new
	properties.
	* include/abg-fwd.h: Forward declare comparison::{diff_context,
	diff_context_sptr, diff_context_wptr, diff, diff_wptr} and
	regex::regex_t_sptr.
	(find_first_data_member_matching_regexp)
	(find_last_data_member_matching_regexp): Declare new functions.
	* include/abg-suppression.h: Inject std::{string, shared_ptr,
	vector} and comparison::{diff, diff_context_sptr} into the suppr
	namespace.  Remove the "abg-comparison.h" header.
	* src/abg-elf-helpers.cc: Include sstream.
	* src/abg-ir.cc (find_first_data_member_matching_regexp)
	(find_last_data_member_matching_regexp): Define new functions.
	* src/abg-suppression.cc
	(type_suppression::insertion_range::eval_boundary): Support
	evaluating "offset_of_first_data_member_regexp" and
	"offset_of_first_data_member_regexp".
	* src/abg-ctf-reader.cc: Include sstream.
	* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-[1-4].txt:
	New test reference outputs.
	* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v[0-4].c:
	Source code of new test input.
	* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v[0-4].o:
	New binary test input.
	* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr:
	New suppression specification.
	* tests/data/Makefile.am: Add the new test input files to source
	distribution.
	* tests/test-diff-suppr.cc (in_out_specs): Add the new test input
	to this test harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 doc/manuals/libabigail-concepts.rst           |  60 +++++++++++-----
 include/abg-fwd.h                             |  33 +++++++++
 include/abg-suppression.h                     |   9 ++-
 src/abg-ctf-reader.cc                         |   1 +
 src/abg-elf-helpers.cc                        |   1 +
 src/abg-ir.cc                                 |  45 ++++++++++++
 src/abg-suppression.cc                        |  64 +++++++++++++-----
 tests/data/Makefile.am                        |  15 ++++
 ...ata-member-inserted-between-1-report-1.txt |   3 +
 ...ata-member-inserted-between-1-report-2.txt |  13 ++++
 ...ata-member-inserted-between-1-report-3.txt |  12 ++++
 ...ata-member-inserted-between-1-report-4.txt |  11 +++
 ...st-has-data-member-inserted-between-1-v0.c |  10 +++
 ...st-has-data-member-inserted-between-1-v0.o | Bin 0 -> 3088 bytes
 ...st-has-data-member-inserted-between-1-v1.c |  10 +++
 ...st-has-data-member-inserted-between-1-v1.o | Bin 0 -> 3088 bytes
 ...st-has-data-member-inserted-between-1-v2.c |  11 +++
 ...st-has-data-member-inserted-between-1-v2.o | Bin 0 -> 3152 bytes
 ...st-has-data-member-inserted-between-1-v3.c |  11 +++
 ...st-has-data-member-inserted-between-1-v3.o | Bin 0 -> 3152 bytes
 ...st-has-data-member-inserted-between-1-v4.c |  10 +++
 ...st-has-data-member-inserted-between-1-v4.o | Bin 0 -> 3152 bytes
 ...t-has-data-member-inserted-between-1.suppr |   7 ++
 tests/test-diff-suppr.cc                      |  42 +++++++++++-
 24 files changed, 328 insertions(+), 40 deletions(-)
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr

new file mode 100644
index 00000000..dfb23703
new file mode 100644
index 00000000..ee7efcb4
new file mode 100644
index 00000000..314803cf
new file mode 100644
index 00000000..13262920
new file mode 100644
index 00000000..094d1d67
  

Patch

diff --git a/doc/manuals/libabigail-concepts.rst b/doc/manuals/libabigail-concepts.rst
index dc5a4a5c..326a346e 100644
--- a/doc/manuals/libabigail-concepts.rst
+++ b/doc/manuals/libabigail-concepts.rst
@@ -493,24 +493,48 @@  names start with the string "private_data_member".
 	   offset of the insertion point of the data member, starting
 	   from the beginning of the relevant structure or class.
 
-	 - the keyword ``end`` which is a named constant which value
-	   equals the offset of the end of the of the structure or
-	   class.
-
-	 - the function call expression
-	   ``offset_of(data-member-name)`` where `data-member-name` is
-	   the name of a given data member of the relevant structure
-	   or class.  The value of this function call expression is an
-	   integer that represents the offset of the data member
-	   denoted by ``data-member-name``.
-
-	 - the function call expression
-	   ``offset_after(data-member-name)`` where `data-member-name`
-	   is the name of a given data member of the relevant
-	   structure or class.  The value of this function call
-	   expression is an integer that represents the offset of the
-	   point that comes right after the region occupied by the
-	   data member denoted by ``data-member-name``.
+.. _suppr_data_member_offset_selector_expressions_label:
+
+	 - data member offset selector expressions, such as:
+
+	     - the keyword ``end`` which is a named constant which value
+	       equals the offset of the end of the of the structure or
+	       class.
+
+	     - the function call expression
+	       ``offset_of(data-member-name)`` where `data-member-name` is
+	       the name of a given data member of the relevant structure
+	       or class.  The value of this function call expression is an
+	       integer that represents the offset of the data member
+	       denoted by ``data-member-name``.
+
+	     - the function call expression
+	       ``offset_after(data-member-name)`` where `data-member-name`
+	       is the name of a given data member of the relevant
+	       structure or class.  The value of this function call
+	       expression is an integer that represents the offset of the
+	       point that comes right after the region occupied by the
+	       data member denoted by ``data-member-name``.
+
+	     - the function call expression
+	       ``offset_of_first_data_member_regexp(data-member-name-regexp)``
+	       where `data-member-name-regexp` is a regular expression
+	       matching a data member.  The value of this function
+	       call expression is an integer that represents the
+	       offset of the first data member which name matches the
+	       regular expression argument.  If no data member of a
+	       given class type matches the regular expression, then
+	       the class type won't match the current directive.
+
+	     - the function call expression
+	       ``offset_of_last_data_member_regexp(data-member-name-regexp)``
+	       where `data-member-name-regexp` is a regular expression
+	       matching a data member.  The value of this function
+	       call expression is an integer that represents the
+	       offset of the last data member which name matches the
+	       regular expression argument.  If no data member of a
+	       given class type matches the regular expression, then
+	       the class type won't match the current directive.
 
   .. _suppr_has_data_member_inserted_between_label:
 
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 4051fab5..fc3f4374 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -11,6 +11,7 @@ 
 #include <stdint.h>
 #include <cstddef>
 #include <cstdlib>
+#include <regex.h>
 #include <list>
 #include <memory>
 #include <ostream>
@@ -62,6 +63,31 @@  typedef unordered_set<string> string_set_type;
 // Pull in relational operators.
 using namespace std::rel_ops;
 
+namespace comparison
+{
+class diff_context;
+
+/// Convenience typedef for a shared pointer of @ref diff_context.
+typedef shared_ptr<diff_context> diff_context_sptr;
+
+/// Convenience typedef for a weak pointer of @ref diff_context.
+typedef weak_ptr<diff_context> diff_context_wptr;
+
+class diff;
+
+/// Convenience typedef for a shared_ptr for the @ref diff class
+typedef shared_ptr<diff> diff_sptr;
+
+/// Convenience typedef for a weak_ptr for the @ref diff class
+typedef weak_ptr<diff> diff_wptr;
+}
+
+namespace regex
+{
+/// A convenience typedef for a shared pointer of regex_t.
+typedef std::shared_ptr<regex_t> regex_t_sptr;
+}// end namespace regex
+
 namespace ir
 {
 
@@ -1472,6 +1498,13 @@  build_internal_underlying_enum_type_name(const string &base_name,
 					 bool is_anonymous,
 					 uint64_t size);
 
+var_decl_sptr
+find_first_data_member_matching_regexp(const class_or_union& t,
+				       const regex::regex_t_sptr& r);
+
+var_decl_sptr
+find_last_data_member_matching_regexp(const class_or_union& t,
+				      const regex::regex_t_sptr& regex);
 } // end namespace ir
 
 using namespace abigail::ir;
diff --git a/include/abg-suppression.h b/include/abg-suppression.h
index a51fdc5a..bfc37a40 100644
--- a/include/abg-suppression.h
+++ b/include/abg-suppression.h
@@ -11,7 +11,7 @@ 
 #include <unordered_set>
 
 #include "abg-ini.h"
-#include "abg-comparison.h"
+#include "abg-ir.h"
 
 namespace abigail
 {
@@ -29,9 +29,12 @@  class fe_iface;
 /// that are defined in this namespace.
 namespace suppr
 {
-
-using namespace abigail::comparison;
 using std::unordered_set;
+using std::string;
+using std::shared_ptr;
+using std::vector;
+using comparison::diff;
+using comparison::diff_context_sptr;
 
 /// Base type of the suppression specifications types.
 ///
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 7db8dbc6..9b34ee2e 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -14,6 +14,7 @@ 
 #include "config.h"
 
 #include <fcntl.h> /* For open(3) */
+#include <sstream>
 #include <iostream>
 #include <memory>
 #include <map>
diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc
index d61114bf..8ffeefb3 100644
--- a/src/abg-elf-helpers.cc
+++ b/src/abg-elf-helpers.cc
@@ -12,6 +12,7 @@ 
 #include <unistd.h>
 #include <limits.h>
 #include <elfutils/libdwfl.h>
+#include <sstream>
 #include "abg-elf-helpers.h"
 #include "abg-tools-utils.h"
 
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index ef19eb41..015aa2b3 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -28,6 +28,7 @@  ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-interned-str.h"
 #include "abg-ir.h"
 #include "abg-corpus.h"
+#include "abg-regex.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -26609,6 +26610,50 @@  build_internal_underlying_enum_type_name(const string &base_name,
   return o.str();
 }
 
+/// Find the first data member of a class or union which name matches
+/// a regular expression.
+///
+/// @param t the class or union to consider.
+///
+/// @param r the regular expression to consider.
+///
+/// @return the data member matched by @p r or nil if none was found.
+var_decl_sptr
+find_first_data_member_matching_regexp(const class_or_union& t,
+				       const regex::regex_t_sptr& r)
+{
+  for (auto data_member : t.get_data_members())
+    {
+      if (regex::match(r, data_member->get_name()))
+	return data_member;
+    }
+
+  return var_decl_sptr();
+}
+
+/// Find the last data member of a class or union which name matches
+/// a regular expression.
+///
+/// @param t the class or union to consider.
+///
+/// @param r the regular expression to consider.
+///
+/// @return the data member matched by @p r or nil if none was found.
+var_decl_sptr
+find_last_data_member_matching_regexp(const class_or_union& t,
+				      const regex::regex_t_sptr& regex)
+{
+  auto d = t.get_data_members().rbegin();
+  auto e = t.get_data_members().rend();
+  for (; d != e; ++d)
+    {
+      if (regex::match(regex, (*d)->get_name()))
+	return *d;
+    }
+
+  return var_decl_sptr();
+}
+
 bool
 ir_traversable_base::traverse(ir_node_visitor&)
 {return true;}
diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc
index 54d2d917..a79deb35 100644
--- a/src/abg-suppression.cc
+++ b/src/abg-suppression.cc
@@ -24,6 +24,7 @@  ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-suppression.h"
 #include "abg-tools-utils.h"
 #include "abg-fe-iface.h"
+#include "abg-comparison.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -36,6 +37,9 @@  namespace abigail
 namespace suppr
 {
 
+// Inject the abigail::comparison namespace in here.
+using namespace comparison;
+
 using std::dynamic_pointer_cast;
 using regex::regex_t_sptr;
 
@@ -1404,32 +1408,56 @@  type_suppression::insertion_range::eval_boundary(const boundary_sptr	boundary,
     {
       ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
       if ((fn_call->get_name() == "offset_of"
-	   || fn_call->get_name() == "offset_after")
+	   || fn_call->get_name() == "offset_after"
+	   || fn_call->get_name() == "offset_of_first_data_member_regexp"
+	   || fn_call->get_name() == "offset_of_last_data_member_regexp")
 	  && fn_call->get_arguments().size() == 1)
 	{
-	  string member_name = fn_call->get_arguments()[0];
-	  for (class_decl::data_members::const_iterator it =
-		 context->get_data_members().begin();
-	       it != context->get_data_members().end();
-	       ++it)
+	  if (fn_call->get_name() == "offset_of"
+	      || fn_call->get_name() == "offset_after")
 	    {
-	      if (!get_data_member_is_laid_out(**it))
-		continue;
-	      if ((*it)->get_name() == member_name)
+	      string member_name = fn_call->get_arguments()[0];
+	      for (class_decl::data_members::const_iterator it =
+		     context->get_data_members().begin();
+		   it != context->get_data_members().end();
+		   ++it)
 		{
-		  if (fn_call->get_name() == "offset_of")
-		    value = get_data_member_offset(*it);
-		  else if (fn_call->get_name() == "offset_after")
+		  if (!get_data_member_is_laid_out(**it))
+		    continue;
+		  if ((*it)->get_name() == member_name)
 		    {
-		      if (!get_next_data_member_offset(context, *it, value))
+		      if (fn_call->get_name() == "offset_of")
+			value = get_data_member_offset(*it);
+		      else if (fn_call->get_name() == "offset_after")
 			{
-			  value = get_data_member_offset(*it) +
-			    (*it)->get_type()->get_size_in_bits();
+			  if (!get_next_data_member_offset(context, *it, value))
+			    {
+			      value = get_data_member_offset(*it) +
+				(*it)->get_type()->get_size_in_bits();
+			    }
 			}
+		      else
+			// We should not reach this point.
+			abort();
+		      return true;
 		    }
-		  else
-		    // We should not reach this point.
-		    abort();
+		}
+	    }
+	  else if (fn_call->get_name() == "offset_of_first_data_member_regexp"
+		   || fn_call->get_name() == "offset_of_last_data_member_regexp")
+	    {
+	      string name_regexp = fn_call->get_arguments()[0];
+	      auto r = regex::compile(name_regexp);
+	      var_decl_sptr dm;
+
+	      if (fn_call->get_name() == "offset_of_first_data_member_regexp")
+		dm = find_first_data_member_matching_regexp(*context, r);
+	      else if (fn_call->get_name() == "offset_of_last_data_member_regexp")
+		dm = find_last_data_member_matching_regexp(*context, r);
+
+	      if (dm)
+		{
+		  value = get_data_member_offset(dm);
 		  return true;
 		}
 	    }
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index a37a364b..a343759e 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -1765,6 +1765,21 @@  test-diff-suppr/test-has-data-member-v0.cc \
 test-diff-suppr/test-has-data-member-v0.o \
 test-diff-suppr/test-has-data-member-v1.cc \
 test-diff-suppr/test-has-data-member-v1.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-v0.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v0.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v1.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v1.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v2.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v2.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v3.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v3.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v4.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v4.o \
+test-diff-suppr/test-has-data-member-inserted-between-1.suppr \
 \
 test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \
 test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt
new file mode 100644
index 00000000..fa4b7506
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt
@@ -0,0 +1,3 @@ 
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added variable
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt
new file mode 100644
index 00000000..605fb3c2
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt
@@ -0,0 +1,13 @@ 
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+  [C] 'S s' was changed at test-has-data-member-inserted-between-1-v2.c:11:1:
+    type of variable changed:
+      type size hasn't changed
+      1 data member insertion:
+        'char data_member_incorrectly_inserted', at offset 32 (in bits) at test-has-data-member-inserted-between-1-v2.c:4:1
+      1 data member change:
+        'char member1' offset changed from 32 to 40 (in bits) (by +8 bits)
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt
new file mode 100644
index 00000000..e87aa121
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt
@@ -0,0 +1,12 @@ 
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+  [C] 'S s' was changed at test-has-data-member-inserted-between-1-v3.c:11:1:
+    size of symbol changed from 20 to 24
+    type of variable changed:
+      type size changed from 160 to 192 (in bits)
+      1 data member insertion:
+        'char data_member_incorrectly_inserted', at offset 160 (in bits) at test-has-data-member-inserted-between-1-v3.c:8:1
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt
new file mode 100644
index 00000000..dccae160
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt
@@ -0,0 +1,11 @@ 
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+  [C] 'S s' was changed at test-has-data-member-inserted-between-1-v4.c:10:1:
+    type of variable changed:
+      type size hasn't changed
+      1 data member insertion:
+        'char data_member_incorrectly_inserted', at offset 40 (in bits) at test-has-data-member-inserted-between-1-v4.c:5:1
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c
new file mode 100644
index 00000000..ea309110
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c
@@ -0,0 +1,10 @@ 
+struct S
+{
+  int member0;
+  char member1;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..f091cba2e0dbef0ed5a03faace02638c0dd0cacf
GIT binary patch
literal 3088
zcmcgt&2Jl35TEthiJMK*q%NNYvPB@;s&D<#D1@LCiwM$+s)|5d5Xh{(FZL39ZSB6K
zMI4a0fCPsgI3P|O_zyVp7jWyJ!Id)yn0Y(T*}m9_2#JyQ&CG8;-{*e$&b@a_jsu1q
zxDBV8K>;2up2}@4w&4=2!*?iGz^M}C((ob;hRPqnWyh%=qOOy=izMc9xjI6ztntdS
zLb<Bt1uZXYc~Q%2P$^g9L_x_}pzu;zH?xp|v$XUQ0vB{;GJ&%K?&{7}=S}Yo?{00|
zL+@9>^KN_YDmJ+8yt-QR+>I+6YtLZqn&VbIZ^t8Nr-l<@SDeklCb-qya<}%@bERi7
z_Y3%ys0irkYN<H1P^qBp26D%7{#;!lMiapgg$+HYlCx2|n5WUf$4M6V6B+q5!;u_y
zW!ivFC!5G#91c5^FpA=&k9ydX&3T5_Ji{&M4Z;-m?|<m;HDC9e&EQth^jnQqtFhT?
z`q$pa!goT&2GP3ii;+4`<ZfRkGL3tvhG}oG`*3?pY;B5@mM{9;WfPRllo*7Wh(Z;L
zymt{NnM{?8L|3W@QYNA)P8vZE>Vxq})}wLsSzPbOsy>XnVK?rF@vxo_6ox68CgHGv
z3&iVDCXb|&<Rp$TK%^4$pU65D&+1fJiz12-4@Gu7nWX<`sdFvCxtw8tZ*RxHhC6rt
zUu>H`O8+p>(JR9rf6a1nXWn?a&xK=J2z2wCUO;lu#R{{?1$}MLm|Q44Dg~<x7Yf>`
z=mK8n8RWw943zrEJ3oV5SUH0Rh^!apb=i2FYtORj%dmv;#aWw*gwyOK=fA|9aQX~A
z&4R%N>(3YP;wyBcfKz@`Z_C1eVf}3je~R_{7EbFz^ij@qkCcC(^@)Xl%K8HfXBEC?
zfzG4pksz~HG~WsVOfNGx>+l2XH!a-NZ!194!W)c3kbOQ<VHdedb3QPVk`EOG^pZf(
z%`ym5IShkHc8~j=I5`}nP0L}oo63_X%wZZPefea_FixZi!4gI!xTE#ncr=pu*ayj2
z$pA07$W+)n;?DmYyMo~~WwV|pTiXa0H_Kz-t0)k5`bW(z?VOz%?fBQwgU;o=`02gk
zOlwv~+CMudxwL6OdX%&2X#3K+pjW6p^~i+-K2+Nra1mkhGk1vo??k)!**OV+Oas!#
zIh&5Q?*UqDjGS*W=#x?)+xI=R&FcRf-cZvg^-r&--G79bof9Fr$Dnx+2qUt6JBZDy
z{}b20qoV+*KD`5W{Rv`}vw>fczT!f^7D1FveZ#+C%#PnJ<$<3VN6uqZ!@r#q|05sB
zI>#Ai;tc<u<Bi?$-|Pd;1`}ueNat1!r1@ixKj45hMCtvr*N@h8Rw<v)ue~mI{q;HV
Ozw`e6jP@eg@qYtbxIbh7

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c
@@ -0,0 +1,10 @@ 
+struct S
+{
+  int member0;
+  char member1;
+  int correctly_inserted_data_member;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..657d4713252ea0a7c8f227446bd556ebbdeb490b
GIT binary patch
literal 3088
zcmd5-OK%)S5U$zTwKpEyv9k%U0G^;Ak|;g9v$2dZa#&#zCnAb0qFf@-Y98&~iFapL
zGi@gk2P7^a!663@9CP4LaO4+|pTU(g2dL`lUQgO%iEyH%>8kqb)zz>0=CixEYL*3>
zEVv2BnnnSh%^%A>DfZwTtiq2dH^6EVWYh2t4Vvor;k;!v_feNg?RgRlx!xS3SeJN1
z;!P>fEegaJr93a?6=>8ONh+Xb%~5!*E+;dWgSD{mE&^v{Wio-a1oraQCF^77Bj-+Q
z(?Rdc;5auOdl@IVYQ4YQa_qH>Yb&o~?UrRX9cRlSXRC#cC|B%eZXN7qVY$=#<jvX}
znEP$~YE%SdyHY9-T~r!qyN2AdtiP6*h*2Z>p|B=<s#$Bbvqc&ie3<6RAmy=39gg`p
z<XH#${d~%!BpCIlK^!OP0QDf^-O~&=Aev+ukHqL{KS^_*2_E<3Km`3FBSga>gWY=%
z+#UZz*Y~{}p6_-$-EL>S>$_LJ!1A{Pp$x2h)n#LGnDXrbPkEL^s0LXy+<vmT!8X>}
zQP*VyHCG?n!^xPp<4OD|X%7<79wlKACW9auwX>mM*cQ*yU{t~x;_W!+2V8J+Vh0$&
zGLG{;;%&imk+*5`Qe<(mzt8f+=`;f}v0;!iva+HzEKu~zLM|S2o-&^u`CjzDo!2Wh
z0lPapTkaLyxvT$T+vI_&9O&rP;m^OTjCSRXr~6zwrlml;xalRN5N)hbMK;K5d%|Qx
z=}{?JZ8%fXjzt^rI#-Ylixnu%AMbnx*|2m1^$=Mt^>to*ywYyvvzK83<I7#^iiA^l
z2P*$L#R;cR<F6UGQsJ!<UVeqHm2k?h>unhLuS);az;~5?&%iGz{h@)=dJ#<vCg)Cd
z<@=8Ov4JZUzEc97M?FV^^jgsxGzd`ip5l6aepdQ*1GnYd3g8=fN8#Y*Psbt%k&CS0
zLoEsZM1V(63V30jgO~A9;Ke*V9N=TRKS7(6gD}ka(M#qa3(^69Ib@WiT!&x@EfU<9
zdNdi2IX?DYIuYE%tIcu|M0)2{1OJg-#5ihMucuDa(}KbE@@V)H3WOd1Q4342U?)a1
z{sZ)&b9q|)>|Uu%D@I1zKQkw}^k_hOR<PM<`qH_eSEx7hD1<$As5Vu=S%k??-y!<H
z6K&&X<|O<D4M<-WY&M#{duTB+a=xxWmy{BjzMrG5YX0A=4b}6c`P1uZ&Ob)X%!v@(
zRiJ(k2qQ9m`-oN5f3E7^mQesypYFR^e~K98?BG|XZ&jh+${@<RzUE&m%#7cu6@g!A
zN0mpbn*VT0{Bw06+bT{o9jEzEDqh<)|J^*$%An)4AL(kU8j}2lir-TKD~QtjXRaTu
bX;mp#onLcZ%=)XR#Q&l8?-#U}$&CL8X>~%d

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c
@@ -0,0 +1,11 @@ 
+struct S
+{
+  int member0;
+  char data_member_incorrectly_inserted;
+  char member1;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o
new file mode 100644
index 0000000000000000000000000000000000000000..4e02e07835e2bef3243fb9fef2f0b414ca85e958
GIT binary patch
literal 3152
zcmd5;&2Jl35TEthiQ7%mq^|fX5Et>0R_xmAMj-^HSVWLit*Q!ygsLL5A20Sc_S)Lr
zghU_#LgIqN1r8iI^1r~514j=03tSKqhcff_jkA4OOOz8M?VFk3e7u>rZ^!=Z?c48E
z3<H=9xB;gcqX56mpUPb+cHttd!1pNEz^D^s(()WFOx5?`l3~;n)MZk0p2S?P)=yBZ
zO1viJnv~}jK1aMR<#{PDNVzWMWvEqaQJg`=m_s+HRApgvDHzuI=Mgw3s~{5?i(oEo
zT`}IUUbk*GHZAmi5iIM5WiDZ{E5=Jp4a;1;yt@1(*3mG`x@B!y<ZLvsDdmct&8>r3
z&n-6_Z$4dl3Ufb;PlYxCbSR+?Vl}i~Lv9$x-%E?cs1bZnSd~3hjMd78JdMn87^hJ`
z7GaY*?Df)#2qJITn|NUu#eLMhKwO8B82KV;&vI~Q89ESpnb*t1dr=&WlSBmB@C4;l
zB$)^y7<dWn-g&>d<G$8(UFW*vHaqQ3r@h{Bn``f4WqV$x40h*g(;j7qvDog5SR_$^
zs+R<V?c>c2dt==`>NM@Xs@8?pU_277a2!5}TKy<%4I|(4qrMjnTgf1^v15_M-mrk%
zh_}L29EePilYM{zb|SFWBhku4nx!r3NQ!nC?eE*^;bf8kne2g=+GMr!esP1mN81<K
z$3n!miv>Et|F*8jY65n5cD9;p_~x$ui`ORaTKPiPvI>7ZEVG)WlYzeb!WAwAn)yU1
zAh~Gb4rOG5{G`vAOehSWg4Kj`1?^Nc0YCK;GGU<vrTTFml#mIFXHW-`l|o;a*yFKY
zS2~><=P|z6HSb6`b@!FZe^GJ5={ZpP6B@2mc&30CC)Bk9PWfL}`i6#or1ZBm{8y#l
z(QrB!qI)@$HB$avrSEGv_xY)Yf1&g*HC(CitrF;-at?y{4C!oY1SonzaXvTty&`%w
zXR=PRnQ|TjxEkJ8I5_FaDD!;eS(5VsOPM&%z@b?Kj-RIBBx2|}q3{p;I9d0{Xp^$%
z`-wPu#Ox(r+!v3A45L_Z2yVe5!9A%5<Izaq4}=qsGvVMjZ>O0T@QqLn{6}^f<EUjm
zPfpWiLF0Tp3|~Qku+v}R+|te2nN^Q}1wH7#&WfLYZz|KWmXY3{o|9a<v>^SEv+1h)
z(!HSR)SY_d!m+wkcU8azgvpP;E&5MDw2hCRlkneYLAsx_>8ktQMT?G+^QHouq!dW^
zy@j^2`hQk0l<TDWX{ze=hluGp5rPjC$a8`)BHg!#SlRx+tNr(66aei{^FiN#f*9p&
z<5Q$>)JA-cY~%fze}aax_y?6d;zM>+30P(R^^EwR)P-!RIA$Ej{5uuTcIJQT7g`xO
wj{Qhir7|S>Un-vOAKiPJfBN~+nU-y}r|z$QuKNBfGve3OPw<auFOnYr4>AZ)uK)l5

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c
@@ -0,0 +1,11 @@ 
+struct S
+{
+  int member0;
+  char member1;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+  char data_member_incorrectly_inserted;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o
new file mode 100644
index 0000000000000000000000000000000000000000..1d6d30fafd91ede6b6e2a31cbb576d6a460574e0
GIT binary patch
literal 3152
zcmcgt&2QsW5Ff`$n_aivmhiE#K(h!$cg1r)T9s1NC8C0M1zN3kg@h0&IQDDeZQ?|>
zTUvnx2#E_47dUX>$o~RI4jeh~FK|If9AM`8P3nDhBq}6E@|&68e7@)B@uzRR{btFs
zfXRYeaHcT|@bmnc+)-i&9)T734&@41Rf23<o}q=Qd>^h_Ry9UlCAH^C%;a+Q6veW_
zD+`~YTvhU%k{6UbujFMVSC#*xP$^f!D20+WhapfZtH$OMu$;@!B5+A{K_;*k!Cu<F
zZoTTf;@qxnIq3a7IL<A{UczQqtQVGQj=g$qb@>VGqh{Gv$Juts*{b2Dv@7mxZUgLU
zX1QH^?a9(r%>6VzB`N~wP(W?ODrmcj+_J2{mKKT8M({ylRqd%{t(LB2X;hA*C<*(K
z4C=JQksS48+=Om7nMgnMhTVx51Yy)i-ScH@mZ3e%unvKjdfhB<H;nvo97{hPo}!${
zIF$kT122ZXJMYwYTQApJEqC2*)!WT>ySdSB)z|J}XZv2N4WfOcE=K85BzO8Ul5yyx
z>c#$G=VWVBY;K6-c3t%KHd>I%BozZM5!8gpnh;!A^kn*xl#ytO<8{}E#$Y^>jbI!+
z2pjz{Z4ASn*9-ezIBdj&6vI*(N8T`p3&a~iA`fLM$w?eyfQTh->{vFac+#NCN)$nO
za3GSS$t3<iOI_#)F60b*ySv-<HGFe7{>5ukcddA#YgvZh|1PrHg_D84``i`I1=`s}
z$RU|%V}&BJL4DHaOg7|(PtIz?rJQyq+JK*W0okxnfKvZB4+_YJ#dD~O$VzTsGz%16
z=yfI2sc{*D^SkDXgwyW6RLKEnZAOIC!}Pco7#CW9Du?GM)Xf}D`MKVvf&ZfQ*A4tJ
zt=}<lIv1k%GNyW@{CiqIFz^qx{)vHquJtbrT&wVn7U-UG?*#D~(m7NJ(Da<<d_MHQ
zB6=xfs!y`nY90f$47{mvaFf$f>h+MPamEKMrSc>Nmxc?ty(9rQmP5}CWbdetll5SX
zHYIz#UM!CvGJCNX_2t7M!!VK@f+biaxT|!3JQ_*-LAcR4l`eksB1t{}P<Q^{*fk8N
zE%SMDwhjvh=i_1cItqlH{e?42Cu8SUGyX;Np!+&2e)_%XOv^?_dVgk4a_P{5^nJ#r
ztLaPkf~Hev>X8X2`cmE10ap+vKmNA3uN}n9oRr~LT9Dq)*mO00@1n)T$azbHby9L<
z`o4v>qW*u<FO>VF{%NY3{RfDdIT3<)HOO;<Fe1~pi&#<p-*o+b6$L=`X+D_sCx}tb
zCO&!kS{LGTWE<CK{xKSg;vbZ<h!5CNCt#KNS2N;&)EBa$<Ct+A^KW%L+nN7iUTAIL
wIQAo5x5|*>f9iO?e{}C@{+Z`TXIfNhU*BKzT+R9`Gve3uFZc(v=gEx!2j78Ee*gdg

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c
@@ -0,0 +1,10 @@ 
+struct S
+{
+  int member0;
+  char member1;
+  char data_member_incorrectly_inserted;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o
new file mode 100644
index 0000000000000000000000000000000000000000..2ed4bccf15f0499b3886733f7071b2dfddd55bb8
GIT binary patch
literal 3152
zcmd5;&2QsW5Ff`$o2}b!yIJwIK)tI4x-0C&*{YPHE)f;9E6{2MLP7`>9Q!r#HgO``
zEv-NTgv14j3miCb<bQ!92aX*07q}oK4$I8*o7DU2NGvBt@|&68e7u?G=Se<${jE1D
zh5<|l+=eraQGj3O&*Y92J8%hB;d_*8VAKgRX?cbgrs_Lz*)Zw}>N2T0Phu`t>!&DI
zC0>(qP0DkNpCewE^1PH6rCgWt3e>8#D9)f_%%K}ps<N=T6pV$1XA!s{s~{5?OJFW<
zUo~E_UbgNuwk-6%4wiM>GMBN~RpYtkhGni@SzCD=>u4Be-LkeVayA;+lyb$+<~G2r
z=axH-SD&mrfw`Z?r$U<mI+Rcwu^QTLA~y`<@8u<8)CfK(tjV4###-fKo<`<4iqohc
zi_oSHyWMmmg2*3sCw>@4aUXR*5Vv3?Mm>?VW;uAX3~dPg%<tym-6#&mNg{%5c#3i=
zl1zjU4EzN4?!Ig9dN0|Y=iYKXyWMKHTN`c9UVj@a+xIhNaN0L)XOtbqVy7=+kwgKi
zei96JPPR6k%?;<cZ99Ectq0A)cqE$PIJ_S<`%%^$Mm@h5_5EnrOa_^Q9g8IPhXve0
zycwqAP-KFfoI?z75`ncIi)JR$ENxOpQgp)T;J`_bCX)on<P7}OA*+-3iyP!UIz5qn
zEJW;h&hdsD{BP@eq$Xf*cX!)f$2WK5U%WPX*UA^VmR0!UL7CMooecEd7p`z2(99=7
z0m(%ZcPJwh<R^X3WI|#16s#s(C}?M*3HYg(kO_+=DAkYipoC0VI)}Q5tQPvZ%pQ;Q
zy3*;?SityV*SsU))ZJGq|0Tr<r{_@Vk7>A4;i&>%oKQClIOTs{>6;q<tI}W7@Q;*!
zSHtOCh~Cectda8XDg8jhxzA5E{0pUjso_e6Z<RpzlyeZoXGmvLBS6tL#rfRm_loGn
zoXI-LX3BXC;AwbE;ozpHqs;Fi&yt)ESjxmn1}@DSaC>PAZX$-h8;aghA1CX<7;RGa
zd%Z*)KV<e3Kkkc%Lxxc-I0Uy~k>IY>gYjr2@CU+;$C+^Pn|IR85BNr?2L2<vf^pO`
zpC_m3u%K~19)_=?K-k%@aBk`3?A)ryzknWeUuVTnzc-a>MaxL<PtQp%9a@ln$k}w&
zed%7%bm~k!a^XZ>s(UKnBEsay-xmERAlku4&q?@iv><(uv+1h)-b0Iyk@J=UZBh!P
z`@V^`vig5kFO=(~`e~}_^@oV*IT3>Q6v%UeFe2Tzi&)wIzpMTCWfTDIPxC?Fe}Wk0
zY~fR+Z`4M7j%?%onSX+YviSRzJmN!kR0&vR{`HLbpVWnHsyJpG$NW1L&vxd2>K9rW
xIF9{DSEVu}`ClrY?;qWJnt%HF(V3QQwXg24ey;ldt25%))lcw`XfKi;{||IgP__U7

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr
@@ -0,0 +1,7 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member_inserted_between =
+    {
+      offset_of_first_data_member_regexp(^__special_padding_space),
+      offset_of_last_data_member_regexp(^__special_padding_space)
+    }
diff --git a/tests/test-diff-suppr.cc b/tests/test-diff-suppr.cc
index a463b341..11be9b9a 100644
--- a/tests/test-diff-suppr.cc
+++ b/tests/test-diff-suppr.cc
@@ -2206,7 +2206,7 @@  InOutSpec in_out_specs[] =
     "data/test-diff-suppr/test-has-data-member-output-2.txt",
     "output/test-diff-suppr/test-has-data-member-output-2.4.txt"
   },
-    {
+  {
     "data/test-diff-suppr/test-has-data-member-v0.o",
     "data/test-diff-suppr/test-has-data-member-v1.o",
     "",
@@ -2216,6 +2216,46 @@  InOutSpec in_out_specs[] =
     "data/test-diff-suppr/test-has-data-member-output-1.txt",
     "output/test-diff-suppr/test-has-data-member-output-1.4.txt"
   },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt"
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
 };