suppression: Better handle soname/filename properties evaluation
authorDodji Seketeli <dodji@redhat.com>
Fri, 21 Feb 2020 10:30:20 +0000 (11:30 +0100)
committerDodji Seketeli <dodji@redhat.com>
Fri, 21 Feb 2020 10:30:20 +0000 (11:30 +0100)
At the moment, we don't make any difference between these two cases:

  1/ A suppression specification has no soname or file name related
  property.

  2/ A suppression specification has a soname or file name related
  property that doesn't match the soname or file name of a given
  corpus.

In both cases 1/ and 2/ libabigail currently assumes that the
suppression specification does not match the given corpus we are
looking at.  This can be wrong, especially if we are in the case 1/
and if the suppression does have other properties that should make it
match the corpus.

This patch fixes this issue.

* include/abg-suppression.h
(suppression_base::has_{soname,file_name}_related_property): Add
new member functions.
* src/abg-dwarf-reader.cc (read_context::suppression_can_match):
Fix the logic to make a difference between the case where the
suppression doesn't have any soname/filename property and the case
where the suppression does have a soname/filename property that
does not match the current binary.
* src/abg-reader.cc (read_context::suppression_can_match):
Likewise.
* src/abg-suppression-priv.h
(suppression_base::priv::matches_soname): If the suppression does
not have any soname related property then it doesn't match the
soname we are looking at.
(suppression_base::priv::matches_binary_name): If the suppression
does not have any filename related property then it doesn't match
the filename we are looking at.
* src/abg-suppression.cc
(suppression_base::has_{soname,file_name}_related_property):
Define new member functions.
(sonames_of_binaries_match): If the suppression does not have any
soname related property then it doesn't match the corpora of the
diff we are looking at.
(names_of_binaries_match): If the suppression does not have any
filename related property then it doesn't match the corpora of the
diff we are looking at.
(type_suppression::suppresses_type): Fix the logic to make a
difference between the case where the suppression doesn't have any
soname/filename property and the case where the suppression does
have a soname/filename property that does not match the current
binary.
(function_suppression::suppresses_{function, function_symbol}):
Likewise.
(variable_suppression::suppresses_{variable, variable_symbol}):
Likewise.
(file_suppression::suppresses_file): Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
include/abg-suppression.h
src/abg-dwarf-reader.cc
src/abg-reader.cc
src/abg-suppression-priv.h
src/abg-suppression.cc

index 02f3fc4..05709d6 100644 (file)
@@ -97,6 +97,9 @@ public:
   const string&
   get_file_name_not_regex_str() const;
 
+  bool
+  has_file_name_related_property() const;
+
   void
   set_soname_regex_str(const string& regexp);
 
@@ -109,6 +112,9 @@ public:
   const string&
   get_soname_not_regex_str() const;
 
+  bool
+  has_soname_related_property() const;
+
   virtual bool
   suppresses_diff(const diff*) const = 0;
 
index 436f610..0697c7a 100644 (file)
@@ -8820,17 +8820,35 @@ public:
   /// Tests if a suppression specification can match ABI artifacts
   /// coming from the binary being analyzed.
   ///
-  /// This tests if the suppression matches the soname of and binary
-  /// name of the ELF binary being analyzed.
+  /// This tests if the suppression can match the soname of and binary
+  /// name of the ELF binary being analyzed.  More precisely, if there
+  /// are any soname or file name property in the suppression and if
+  /// those do *NOT* match the current binary, then the function
+  /// returns false.
   ///
   /// @param s the suppression specification to consider.
+  ///
+  /// @return true iff either there are no soname/filename related
+  /// property on the suppression, or if none of the soname/filename
+  /// properties of the suppression match the current binary.
   bool
   suppression_can_match(const suppr::suppression_base& s) const
   {
-    if (s.priv_->matches_soname(dt_soname())
-       && s.priv_->matches_binary_name(elf_path()))
-      return true;
-    return false;
+    if (!s.priv_->matches_soname(dt_soname()))
+      if (s.has_soname_related_property())
+       // The suppression has some SONAME related properties, but
+       // none of them match the SONAME of the current binary.  So
+       // the suppression cannot match the current binary.
+       return false;
+
+    if (!s.priv_->matches_binary_name(elf_path()))
+      if (s.has_file_name_related_property())
+       // The suppression has some file_name related properties, but
+       // none of them match the file name of the current binary.  So
+       // the suppression cannot match the current binary.
+       return false;
+
+    return true;
   }
 
   /// Test whether if a given function suppression matches a function
index 30b9abc..7c8a56a 100644 (file)
@@ -948,10 +948,22 @@ public:
   suppression_can_match(const suppr::suppression_base& s) const
   {
     corpus_sptr corp = get_corpus();
-    if (s.priv_->matches_soname(corp->get_soname())
-       && s.priv_->matches_binary_name(corp->get_path()))
-      return true;
-    return false;
+
+    if (!s.priv_->matches_soname(corp->get_soname()))
+      if (s.has_soname_related_property())
+       // The suppression has some SONAME related properties, but
+       // none of them match the SONAME of the current binary.  So
+       // the suppression cannot match the current binary.
+       return false;
+
+    if (!s.priv_->matches_binary_name(corp->get_path()))
+      if (s.has_file_name_related_property())
+       // The suppression has some file_name related properties, but
+       // none of them match the file name of the current binary.  So
+       // the suppression cannot match the current binary.
+       return false;
+
+    return true;
   }
 
   /// Test whether if a given function suppression matches a function
index 449814c..d872168 100644 (file)
@@ -179,32 +179,72 @@ public:
     return soname_not_regex_;
   }
 
+  /// Test if the current suppression matches a given SONAME.
+  ///
+  /// @param soname the SONAME to consider.
+  ///
+  /// @return true iff the suppression matches the SONAME denoted by
+  /// @p soname.
+  ///
+  /// Note that if the suppression contains no property that is
+  /// related to SONAMEs, the function returns false.
   bool
   matches_soname(const string& soname) const
   {
+    bool has_regexp = false;
     if (sptr_utils::regex_t_sptr regexp = get_soname_regex())
-      if (regexec(regexp.get(), soname.c_str(), 0, NULL, 0) != 0)
-       return false;
+      {
+       has_regexp = true;
+       if (regexec(regexp.get(), soname.c_str(), 0, NULL, 0) != 0)
+         return false;
+      }
 
     if (sptr_utils::regex_t_sptr regexp = get_soname_not_regex())
-      if (regexec(regexp.get(), soname.c_str(), 0, NULL, 0) == 0)
+      {
+       has_regexp = true;
+       if (regexec(regexp.get(), soname.c_str(), 0, NULL, 0) == 0)
+         return false;
+      }
+
+      if (!has_regexp)
        return false;
 
     return true;
   }
 
+  /// Test if the current suppression matches the full file path to a
+  /// given binary.
+  ///
+  /// @param binary_name the full path to the binary.
+  ///
+  /// @return true iff the suppression matches the path denoted by @p
+  /// binary_name.
+  ///
+  /// Note that if the suppression contains no property that is
+  /// related to file name, the function returns false.
   bool
   matches_binary_name(const string& binary_name) const
   {
+    bool has_regexp = false;
+
     if (sptr_utils::regex_t_sptr regexp = get_file_name_regex())
-      if (regexec(regexp.get(), binary_name.c_str(),
-                 0, NULL, 0) != 0)
-       return false;
+      {
+       has_regexp = true;
+       if (regexec(regexp.get(), binary_name.c_str(),
+         0, NULL, 0) != 0)
+         return false;
+      }
 
     if (sptr_utils::regex_t_sptr regexp = get_file_name_not_regex())
-      if (regexec(regexp.get(), binary_name.c_str(),
-                 0, NULL, 0) == 0)
-       return false;
+      {
+       has_regexp = true;
+       if (regexec(regexp.get(), binary_name.c_str(),
+         0, NULL, 0) == 0)
+         return false;
+      }
+
+    if (!has_regexp)
+      return false;
 
     return true;
   }
index 05d3858..663749d 100644 (file)
@@ -184,6 +184,18 @@ const string&
 suppression_base::get_file_name_not_regex_str() const
 {return priv_->file_name_not_regex_str_;}
 
+/// Test if the current suppression has a property related to file
+/// name.
+///
+/// @return true iff the current suppression has either a
+/// file_name_regex or a file_name_not_regex property.
+bool
+suppression_base::has_file_name_related_property() const
+{
+  return (!(get_file_name_regex_str().empty()
+           && get_file_name_not_regex_str().empty()));
+}
+
 /// Setter of the "soname_regex_str property of the current instance
 /// of @ref suppression_base.
 ///
@@ -234,6 +246,17 @@ const string&
 suppression_base::get_soname_not_regex_str() const
 {return priv_->soname_not_regex_str_;}
 
+/// Test if the current suppression has a property related to SONAMEs.
+///
+/// @return true iff the current suppression has either a soname_regex
+/// or a soname_not_regex property.
+bool
+suppression_base::has_soname_related_property() const
+{
+  return (!(get_soname_regex_str().empty()
+           && get_soname_not_regex_str().empty()));
+}
+
 /// Check if the SONAMEs of the two binaries being compared match the
 /// content of the properties "soname_regexp" and "soname_not_regexp"
 /// of the current suppression specification.
@@ -254,6 +277,9 @@ sonames_of_binaries_match(const suppression_base& suppr,
   string first_soname = ctxt.get_corpus_diff()->first_corpus()->get_soname(),
     second_soname = ctxt.get_corpus_diff()->second_corpus()->get_soname();
 
+  if (!suppr.has_soname_related_property())
+    return false;
+
   if (!suppr.priv_->matches_soname(first_soname)
       && !suppr.priv_->matches_soname(second_soname))
     return false;
@@ -281,6 +307,9 @@ names_of_binaries_match(const suppression_base& suppr,
   string first_binary_path = ctxt.get_corpus_diff()->first_corpus()->get_path(),
     second_binary_path = ctxt.get_corpus_diff()->second_corpus()->get_path();
 
+  if (!suppr.has_file_name_related_property())
+    return false;
+
   if (!suppr.priv_->matches_binary_name(first_binary_path)
       && !suppr.priv_->matches_binary_name(second_binary_path))
     return false;
@@ -850,17 +879,18 @@ type_suppression::suppresses_type(const type_base_sptr& type,
 {
   if (ctxt)
     {
-      // Check if the names of the binaries match
+      // Check if the names of the binaries match the suppression
       if (!names_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_file_name_related_property())
+         return false;
 
-      // Check if the sonames of the binaries match
+      // Check if the sonames of the binaries match the suppression
       if (!sonames_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_soname_related_property())
+         return false;
     }
 
   return suppresses_type(type);
-
 }
 
 /// Test if an instance of @ref type_suppression matches a given type.
@@ -2419,16 +2449,19 @@ function_suppression::suppresses_function(const function_decl* fn,
   if (!(get_change_kind() & k))
     return false;
 
-  // Check if the name and soname of the binaries match
+  // Check if the name and soname of the binaries match the current
+  // suppr spec
   if (ctxt)
     {
-      // Check if the name of the binaries match
+      // Check if the name of the binaries match the current suppr spec
       if (!names_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_file_name_related_property())
+         return false;
 
-      // Check if the soname of the binaries match
+      // Check if the soname of the binaries match the current suppr spec
       if (!sonames_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_soname_related_property())
+         return false;
     }
 
   string fname = fn->get_qualified_name();
@@ -2752,16 +2785,21 @@ function_suppression::suppresses_function_symbol(const elf_symbol* sym,
   ABG_ASSERT(k & function_suppression::ADDED_FUNCTION_CHANGE_KIND
         || k & function_suppression::DELETED_FUNCTION_CHANGE_KIND);
 
-  // Check if the name and soname of the binaries match
+  // Check if the name and soname of the binaries match the current
+  // suppr spect
   if (ctxt)
     {
-      // Check if the name of the binaries match
+      // Check if the name of the binaries match the current
+      // suppr spect
       if (!names_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_file_name_related_property())
+         return false;
 
-      // Check if the soname of the binaries match
+      // Check if the soname of the binaries match the current
+      // suppr spect
       if (!sonames_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_soname_related_property())
+         return false;
     }
 
   string sym_name = sym->get_name(), sym_version = sym->get_version().str();
@@ -3715,13 +3753,17 @@ variable_suppression::suppresses_variable(const var_decl* var,
   // Check if the name and soname of the binaries match
   if (ctxt)
     {
-      // Check if the name of the binaries match
+      // Check if the name of the binaries match the current
+      // suppr spec
       if (!names_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_file_name_related_property())
+         return false;
 
-      // Check if the soname of the binaries match
+      // Check if the soname of the binaries match the current suppr
+      // spec
       if (!sonames_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_soname_related_property())
+         return false;
     }
 
   string var_name = var->get_qualified_name();
@@ -3871,16 +3913,20 @@ variable_suppression::suppresses_variable_symbol(const elf_symbol* sym,
   ABG_ASSERT(k & ADDED_VARIABLE_CHANGE_KIND
         || k & DELETED_VARIABLE_CHANGE_KIND);
 
-  // Check if the name and soname of the binaries match
+  // Check if the name and soname of the binaries match the current
+  // suppr spec.
   if (ctxt)
     {
-      // Check if the name of the binaries match
+      // Check if the name of the binaries match the current suppr
+      // spec
       if (!names_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_file_name_related_property())
+         return false;
 
-      // Check if the soname of the binaries match
+      // Check if the soname of the binaries match the current suppr spec
       if (!sonames_of_binaries_match(*this, *ctxt))
-       return false;
+       if (has_soname_related_property())
+         return false;
     }
 
   string sym_name = sym->get_name(), sym_version = sym->get_version().str();
@@ -4227,15 +4273,26 @@ file_suppression::suppresses_file(const string& file_path)
   string fname;
   tools_utils::base_name(file_path, fname);
 
+  bool has_regexp = false;
+
   if (sptr_utils::regex_t_sptr regexp =
       suppression_base::priv_->get_file_name_regex())
-    if (regexec(regexp.get(), fname.c_str(), 0, NULL, 0) != 0)
-      return false;
+    {
+      has_regexp = true;
+      if (regexec(regexp.get(), fname.c_str(), 0, NULL, 0) != 0)
+       return false;
+    }
 
   if (sptr_utils::regex_t_sptr regexp =
       suppression_base::priv_->get_file_name_not_regex())
-    if (regexec(regexp.get(), fname.c_str(), 0, NULL, 0) == 0)
-      return false;
+    {
+      has_regexp = true;
+      if (regexec(regexp.get(), fname.c_str(), 0, NULL, 0) == 0)
+       return false;
+    }
+
+  if (!has_regexp)
+    return false;
 
   return true;
 }