From: Dodji Seketeli Date: Fri, 21 Feb 2020 11:32:42 +0000 (+0100) Subject: abixml-reader: Support SONAME related properties on file suppression X-Git-Tag: upstream/1.7~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6a0e7e120b18c51ce7cc2d273697b7440e1ac99e;p=platform%2Fupstream%2Flibabigail.git abixml-reader: Support SONAME related properties on file suppression When comparing binary files (using abidiff for instance) libabigail can interpret the [suppress_file] section of a suppression specification. If the suppression specification matches either of the compared files, no comparison is performed. At the moment, that doesn't work when comparing abixml files. Thus, this patch implements that feature for abixml files. With this patch, one can now write a suppression specification like this: [suppress_file] soname_regexp = or [suppress_file] file_name_regexp = If either abixml file has a soname matched by such a regexp, then no comparison is performed. * doc/manuals/libabigail-concepts.rst: Update the documentation to mention soname_regexp and soname_not_regexp is supported in the [suppress_file] section. * include/abg-suppression.h (suppression_matches_soname) (suppression_matches_soname_or_filename): Declare new functions. Make them be friends of class suppression_base. * src/abg-reader.cc (read_context::corpus_is_suppressed_by_soname_or_filename): Define new member function. (read_corpus_from_input): Apply file suppression. * src/abg-suppression.cc (read_file_suppression): Support "soname_regexp" and "soname_not_regexp" in the [suppress_file] section. (suppression_matches_soname) (suppression_matches_soname_or_filename): Define new functions. * tests/data/test-diff-suppr/libtest48-soname-abixml-report-{1,2}.txt: New test reference output files. Likewise. * tests/data/test-diff-suppr/libtest48-soname-abixml-suppr.txt: New test suppression file. * tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-{2,3,4}.txt:: Likewise. * tests/data/test-diff-suppr/libtest48-soname-abixml-v{0,1}.so: New test binary input files. * tests/data/test-diff-suppr/libtest48-soname-abixml-v{0,1}.so.abi: New abixml for the binary input files above. * tests/data/test-diff-suppr/test48-soname-abixml-v{0,1}.c: Source code of the binary input files above. * tests/data/Makefile.am: Add the above test material to source distribution. * tests/test-diff-suppr.cc (in_out_specs): Add the test input above to this test harness. Signed-off-by: Dodji Seketeli --- diff --git a/doc/manuals/libabigail-concepts.rst b/doc/manuals/libabigail-concepts.rst index 6565d30b..607edee6 100644 --- a/doc/manuals/libabigail-concepts.rst +++ b/doc/manuals/libabigail-concepts.rst @@ -197,10 +197,10 @@ suppress ABI change reports for a particular kind of ABI artifact. $$$$$$$$$$$$$$$$$$$ This directive prevents a given tool from loading a file (binary or -not) if its file name matches certain properties. Thus, if the tool -is meant to compare the ABIs of two files, and if the directive -prevents it from loading either one of the files, then no comparison -is performed. +abixml file) if its file name or other properties match certain +properties. Thus, if the tool is meant to compare the ABIs of two +files, and if the directive prevents it from loading either one of the +files, then no comparison is performed. Note that for the ``[suppress_file]`` directive to work, at least one of the following properties must be provided: @@ -228,6 +228,28 @@ The potential properties of this sections are listed below: the regular expression specified as value of this property. +* ``soname_regexp`` + + Usage: + + ``soname_regexp`` ``=`` <:ref:`regular-expression `> + + Prevents the system from loading the file which contains a SONAME + property that matches the regular expression of this property. Note + that this property also works on an abixml file if it contains a + SONAME property. + +* ``soname_not_regexp`` + + Usage: + + ``soname_not_regexp`` ``=`` <:ref:`regular-expression `> + + Prevents the system from loading the file which contains a SONAME + property that does *NOT* match the regular expression of this + property. Note that this property also works on an abixml file if + it contains a SONAME property. + * ``label`` Usage: diff --git a/include/abg-suppression.h b/include/abg-suppression.h index 05709d69..1ccb7762 100644 --- a/include/abg-suppression.h +++ b/include/abg-suppression.h @@ -119,6 +119,15 @@ public: suppresses_diff(const diff*) const = 0; virtual ~suppression_base(); + + friend bool + suppression_matches_soname(const string& soname, + const suppression_base& suppr); + + friend bool + suppression_matches_soname_or_filename(const string& soname, + const string& filename, + const suppression_base& suppr); }; // end class suppression_base void @@ -826,6 +835,15 @@ file_suppression_sptr file_is_suppressed(const string& file_path, const suppressions_type& suppressions); +bool +suppression_matches_soname(const string& soname, + const suppression_base& suppr); + +bool +suppression_matches_soname_or_filename(const string& soname, + const string& filename, + const suppression_base& suppr); + const char* get_private_types_suppr_spec_label(); diff --git a/src/abg-reader.cc b/src/abg-reader.cc index 7c8a56a9..915b2c13 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -794,6 +794,35 @@ public: get_suppressions() const {return const_cast(this)->get_suppressions();} + /// Test if there are suppression specifications (associated to the + /// current corpus) that match a given SONAME or file name. + /// + /// @param soname the SONAME to consider. + /// + /// @param the file name to consider. + /// + /// @return true iff there are suppression specifications (associated to the + /// current corpus) that match the SONAME denoted by @p soname or + /// the file name denoted by @p filename. + bool + corpus_is_suppressed_by_soname_or_filename(const string& soname, + const string& filename) + { + using suppr::suppressions_type; + using suppr::file_suppression_sptr; + using suppr::is_file_suppression; + + for (suppressions_type::const_iterator s = get_suppressions().begin(); + s != get_suppressions().end(); + ++s) + if (file_suppression_sptr suppr = is_file_suppression(*s)) + if (suppr::suppression_matches_soname_or_filename(soname, filename, + *suppr)) + return true; + + return false; + } + /// Add a given function to the set of exported functions of the /// current corpus, if the function satisfies the different /// constraints requirements. @@ -1860,8 +1889,13 @@ read_corpus_from_input(read_context& ctxt) ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get()); xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(reader, "path"); + string path; + if (path_str) - corp.set_path(reinterpret_cast(path_str.get())); + { + path = reinterpret_cast(path_str.get()); + corp.set_path(path); + } xml::xml_char_sptr architecture_str = XML_READER_GET_ATTRIBUTE(reader, "architecture"); @@ -1871,8 +1905,24 @@ read_corpus_from_input(read_context& ctxt) xml::xml_char_sptr soname_str = XML_READER_GET_ATTRIBUTE(reader, "soname"); + string soname; + if (soname_str) - corp.set_soname(reinterpret_cast(soname_str.get())); + { + soname = reinterpret_cast(soname_str.get()); + corp.set_soname(soname); + } + + // Apply suppression specifications here to honour: + // + // [suppress_file] + // (soname_regexp + // |soname_not_regexp + // |file_name_regexp + // |file_name_not_regexp) = + if ((!soname.empty() || !path.empty()) + && ctxt.corpus_is_suppressed_by_soname_or_filename(soname, path)) + return nil; node = xmlTextReaderExpand(reader.get()); if (!node) diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc index 663749db..91286f25 100644 --- a/src/abg-suppression.cc +++ b/src/abg-suppression.cc @@ -4335,14 +4335,39 @@ read_file_suppression(const ini::config::section& section) ? file_name_not_regex_prop->get_value()->as_string() : ""; + ini::simple_property_sptr soname_regex_prop = + is_simple_property(section.find_property("soname_regexp")); + string soname_regex_str = + soname_regex_prop ? soname_regex_prop->get_value()->as_string() : ""; + + ini::simple_property_sptr soname_not_regex_prop = + is_simple_property(section.find_property("soname_not_regexp")); + string soname_not_regex_str = + soname_not_regex_prop + ? soname_not_regex_prop->get_value()->as_string() + : ""; + if (file_name_regex_str.empty() - && file_name_not_regex_str.empty()) + && file_name_not_regex_str.empty() + && soname_regex_str.empty() + && soname_not_regex_str.empty()) return result; - result.reset(new file_suppression(label_str, file_name_regex_str, file_name_not_regex_str)); + if (!soname_regex_str.empty()) + { + result->set_soname_regex_str(soname_regex_str); + result->set_drops_artifact_from_ir(true); + } + + if (!soname_not_regex_str.empty()) + { + result->set_soname_not_regex_str(soname_not_regex_str); + result->set_drops_artifact_from_ir(true); + } + return result; } @@ -4382,6 +4407,42 @@ file_is_suppressed(const string& file_path, return file_suppression_sptr(); } +/// Test if a given SONAME is matched by a given suppression +/// specification. +/// +/// @param soname the SONAME to consider. +/// +/// @param suppr the suppression specification to consider. +/// +/// @return true iff a given SONAME is matched by a given suppression +/// specification. +bool +suppression_matches_soname(const string& soname, + const suppression_base& suppr) +{ + return suppr.priv_->matches_soname(soname); +} + +/// Test if a given SONAME or file name is matched by a given +/// suppression specification. +/// +/// @param soname the SONAME to consider. +/// +/// @param filename the file name to consider. +/// +/// @param suppr the suppression specification to consider. +/// +/// @return true iff either @p soname or @p filename is matched by the +/// suppression specification @p suppr. +bool +suppression_matches_soname_or_filename(const string& soname, + const string& filename, + const suppression_base& suppr) +{ + return (suppression_matches_soname(soname, suppr) + || suppr.priv_->matches_binary_name(filename)); +} + /// @return the name of the artificial private type suppression /// specification that is auto-generated by libabigail to suppress /// change reports about types that are not defined in public headers. diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index a38fadfd..5031e6d3 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -1273,6 +1273,18 @@ test-diff-suppr/test47-non-reachable-types-v1.o \ test-diff-suppr/test47-non-reachable-types-v0.o.alltypes.abixml \ test-diff-suppr/test47-non-reachable-types-v1.o.alltypes.abixml \ test-diff-suppr/test47-non-reachable-types-report-10.txt \ +test-diff-suppr/libtest48-soname-abixml-v0.so \ +test-diff-suppr/libtest48-soname-abixml-v0.so.abi \ +test-diff-suppr/libtest48-soname-abixml-v1.so \ +test-diff-suppr/libtest48-soname-abixml-v1.so.abi \ +test-diff-suppr/test48-soname-abixml-v0.c \ +test-diff-suppr/test48-soname-abixml-v1.c \ +test-diff-suppr/libtest48-soname-abixml-report-1.txt \ +test-diff-suppr/libtest48-soname-abixml-report-2.txt \ +test-diff-suppr/libtest48-soname-abixml-suppr.txt \ +test-diff-suppr/libtest48-soname-abixml-suppr-2.txt \ +test-diff-suppr/libtest48-soname-abixml-suppr-3.txt \ +test-diff-suppr/libtest48-soname-abixml-suppr-4.txt \ \ 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/libtest48-soname-abixml-report-1.txt b/tests/data/test-diff-suppr/libtest48-soname-abixml-report-1.txt new file mode 100644 index 00000000..9ba2b126 --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-report-1.txt @@ -0,0 +1,16 @@ +ELF SONAME changed +Functions changes summary: 0 Removed, 1 Changed, 0 Added function +Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + +SONAME changed from 'test48-soname-abixml-v0' to 'test48-soname-abixml-v1' + +1 function with some indirect sub-type change: + + [C]'function void foo(S*)' at test48-soname-abixml-v1.c:8:1 has some indirect sub-type changes: + parameter 1 of type 'S*' has sub-type changes: + in pointed to type 'struct S' at test48-soname-abixml-v1.c:1:1: + type size changed from 32 to 64 (in bits) + 1 data member insertion: + 'char S::m1', at offset 32 (in bits) at test48-soname-abixml-v1.c:4:1 + + diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-report-2.txt b/tests/data/test-diff-suppr/libtest48-soname-abixml-report-2.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-2.txt b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-2.txt new file mode 100644 index 00000000..c9b7ad46 --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-2.txt @@ -0,0 +1,2 @@ +[suppress_file] + soname_regexp = test48-soname-abixml-v.* diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-3.txt b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-3.txt new file mode 100644 index 00000000..c69c2504 --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-3.txt @@ -0,0 +1,2 @@ +[suppress_file] + file_name_regexp = ^libtest48-soname-abixml-v.*$ diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-4.txt b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-4.txt new file mode 100644 index 00000000..1a205275 --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr-4.txt @@ -0,0 +1,2 @@ +[suppress_file] + file_name_regexp = ^libtest48-soname-abixml-v.*$ diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr.txt b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr.txt new file mode 100644 index 00000000..08d61c0f --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-suppr.txt @@ -0,0 +1,2 @@ +[suppress_file] + soname_regexp = test48-soname-abixml-v.* diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-v0.so b/tests/data/test-diff-suppr/libtest48-soname-abixml-v0.so new file mode 100755 index 00000000..e805adf0 Binary files /dev/null and b/tests/data/test-diff-suppr/libtest48-soname-abixml-v0.so differ diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-v0.so.abi b/tests/data/test-diff-suppr/libtest48-soname-abixml-v0.so.abi new file mode 100644 index 00000000..f9fa8e5a --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-v0.so.abi @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-v1.so b/tests/data/test-diff-suppr/libtest48-soname-abixml-v1.so new file mode 100755 index 00000000..a10a9f8b Binary files /dev/null and b/tests/data/test-diff-suppr/libtest48-soname-abixml-v1.so differ diff --git a/tests/data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi b/tests/data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi new file mode 100644 index 00000000..060ceb4c --- /dev/null +++ b/tests/data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-diff-suppr/test48-soname-abixml-v0.c b/tests/data/test-diff-suppr/test48-soname-abixml-v0.c new file mode 100644 index 00000000..3ea3ca70 --- /dev/null +++ b/tests/data/test-diff-suppr/test48-soname-abixml-v0.c @@ -0,0 +1,8 @@ +struct S +{ + int m0; +}; + +void +foo(struct S *a __attribute__((unused))) +{} diff --git a/tests/data/test-diff-suppr/test48-soname-abixml-v1.c b/tests/data/test-diff-suppr/test48-soname-abixml-v1.c new file mode 100644 index 00000000..fc74925d --- /dev/null +++ b/tests/data/test-diff-suppr/test48-soname-abixml-v1.c @@ -0,0 +1,9 @@ +struct S +{ + int m0; + char m1; +}; + +void +foo(struct S *a __attribute__((unused))) +{} diff --git a/tests/test-diff-suppr.cc b/tests/test-diff-suppr.cc index b513a4b4..26de0090 100644 --- a/tests/test-diff-suppr.cc +++ b/tests/test-diff-suppr.cc @@ -1958,6 +1958,56 @@ InOutSpec in_out_specs[] = "data/test-diff-suppr/test47-non-reachable-types-report-10.txt", "output/test-diff-suppr/test47-non-reachable-types-report-10.txt" }, + { + "data/test-diff-suppr/libtest48-soname-abixml-v0.so", + "data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi", + "", + "", + "", + "--no-default-suppression", + "data/test-diff-suppr/libtest48-soname-abixml-report-1.txt", + "output/test-diff-suppr/libtest48-soname-abixml-report-1.txt" + }, + { + "data/test-diff-suppr/libtest48-soname-abixml-v0.so", + "data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi", + "", + "", + "data/test-diff-suppr/libtest48-soname-abixml-suppr.txt", + "--no-default-suppression", + "data/test-diff-suppr/libtest48-soname-abixml-report-2.txt", + "output/test-diff-suppr/libtest48-soname-abixml-report-2.txt" + }, + { + "data/test-diff-suppr/libtest48-soname-abixml-v0.so", + "data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi", + "", + "", + "data/test-diff-suppr/libtest48-soname-abixml-suppr-2.txt", + "--no-default-suppression", + "data/test-diff-suppr/libtest48-soname-abixml-report-1.txt", + "output/test-diff-suppr/libtest48-soname-abixml-report-1.txt" + }, + { + "data/test-diff-suppr/libtest48-soname-abixml-v0.so", + "data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi", + "", + "", + "data/test-diff-suppr/libtest48-soname-abixml-suppr-3.txt", + "--no-default-suppression", + "data/test-diff-suppr/libtest48-soname-abixml-report-2.txt", + "output/test-diff-suppr/libtest48-soname-abixml-report-2.txt" + }, + { + "data/test-diff-suppr/libtest48-soname-abixml-v0.so", + "data/test-diff-suppr/libtest48-soname-abixml-v1.so.abi", + "", + "", + "data/test-diff-suppr/libtest48-soname-abixml-suppr-4.txt", + "--no-default-suppression", + "data/test-diff-suppr/libtest48-soname-abixml-report-1.txt", + "output/test-diff-suppr/libtest48-soname-abixml-report-1.txt" + }, // This should be the last entry {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} };