libabigail/tests/test-diff-filter.cc
Dodji Seketeli 46b1ab08b0 Bug 27995 - Self comparison error from abixml file
There are several self comparison issues uncovered by comparing the
file test-PR27995.abi (provided in the bug report) against itself.
This patch address them all as well as the regressions induced on some
of the test suite and then and updates the other reference test suite
output that need it.

In the equals overload for decl_base, we compare the non-internal
versions of qualified decl names.  For var_decls of anonymous class or
union types, the non-internal version is the flat-representation of
the type.  Thus a benign change in a data member name of the anonymous
type might cause the equals function to consider the var_decls to be
wrongly different.  The internal version of the qualified decl name
should return a name that is stable for types, irrespective of these
benign variations.  The patch thus makes the equals overload for
decl_base to compare internal versions of qualified decl names instead.

The patch ensures that enum_type_decl::get_pretty_representation
return and internal pretty representation that is "stable" for
anonymous types.  Basically, all anonymous enums will have the same of
name that looks like "__anonymous_enum__".  This is to ensure two
things: first, that all anonymous enums are compared against each
other during type canonicalization, ensuring that when two anonymous
enums are canonically different, it really is because of changes in
their enumerators or basic type, not because of anything having to do
with their artificial names.  Second, that in the equals overload for
decl_base, their internal qualified name always compare equal.  This
nullifies the risk of having anonymous types compare different because
of their (non existent) name.  This is because libabigail's dwarf
reader assigns artificial unique names to anonymous types, so we don't
want to use these during actual type comparison.

We do something similar for class_decl::get_pretty_representation and
union_decl::get_pretty_representation where the pretty internal
representation for class/union decl would now be
__anonymous_{struct,union}__.

The patch scouts the uses of get_pretty_representation() to make sure
to use avoid using the internal-form of the pretty representations
when it's not warranted.  It also updates the doxygen comments of the
overloads of that function.

In the abixml reader, we were wrongly canonicalizing array types
early, even before they were fully created.  The was leading to
spurious type chances down the road.

The patch also fixes the caching of the name of function types by
making it consistent with caching of the names of the other types of
the system.  The idea is that we don't cache the name of a function
type until it's canonicalize.  This is because the type might be
edited during its pre-canonicalization life time; and that editing
might change its name.  However once the type is canonicalized, it
becomes immutable.  At that point we can cache its name, for
performance purposes.  Note that we need to do that both for the
"internal version" of the type name (used for canonilization purposes)
and the "non-internal version" one, which is used for other purposes.

This caching scheme wasn't respected for function types, so we were
caching a potentially wrong name for the type after its
canonicalization.

Last but not least, there is a problem that makes canonical type
comparison different from structural type comparison.
Let's consider these two declarations:

    typedef int FirstInt;
    typedef int SecondInt;

Now, consider these two pointer types: FirstInt* and SecondInt*;
These two pointer types are canonically different because they have
different type names.  This is because during type canonicalization,
types with the same "pretty representation" are compared against each
other.  So types with different type names will certainly have
different pretty representations and won't be compared; they are thus
going to have different canonical types.

However, FirstInt* and SecondInt* do compare equal, structurally,
because the equals overload for pointer_type_def compares the
pointed-to types of pointers by peeling off typedefs.  So, here, as
both pointed-to types are 'int' when the typedefs are peeled off, the
two pointers structurally compare equal.  This discrepancy between
structural and canonical equality introduces subtle and spurious type
changes depending on the order in which types are canonicalized.  For
instance:

    struct {FirstInt* m0;};   /* First type.  */

    struct {SecondInt* m0;};  /* Second type. */

If FirstInt* and SecondInt* are canonicalized before their containing
anonymous types, then the two anonymous types will compare different
(because FirstInt* and SecondInt* compare different) and have
different canonical types.  If, however, the anonymous types are
canonicalized before FirstInt* and SecondInt*, then will compare equal
because FirstInt* and SecondInt* are structurally equivalent.
FirstInt* and SecondInt* will be canonicalized latter and have
different canonical types (because they have different type names)
despite being structurally equivalent.

The change in the order of canonicalization can happen when
canonicalizing types from a corpus coming from DWARF as opposed to
canonicalizing types from a corpus coming from abixml.

The patch fixes this discrepancy by not peeling off typedefs from the
pointed-to types when comparing pointers.  Note that this makes us
regress on bug https://sourceware.org/bugzilla/show_bug.cgi?id=27236,
where the typedef peeling was introduced.  In hindsight, introducing
that typedef peeling was a mistake.  I'll try to address that bug
again in a subsequent patch.

	* doc/manuals/abidiff.rst: Add documentation for the --debug
	option.
	* src/abg-ir.cc (equals): In the overload for decl_base consider
	the internal version of qualified decl name.  In the overload for
	pointer_type_def do not peel typedefs off from the compared
	pointed-to types.  In the overload for typedef_decl compare the
	typedef as a decl as well.  In the overload for var_decl, compare
	variables that have the same ELF symbols without taking into
	account their qualified name, rather than their name.  Stop
	comparing data member without considering their names.
	In the overload for class_or_union, when a decl-only class that is
	ODR-relevant is compared against another type, assume that
	equality if names are equal.  This is useful in environments where
	some TUs are ODR-relevant and others aren't.
	(*::get_pretty_representation): Update doxygen comments.
	(enum_type_decl::get_pretty_representation): Return an internal
	pretty representation that is stable across all anonymous enums.
	(var_decl::get_anon_dm_reliable_name): Use the non-internal pretty
	representation for anonymous data members.
	(function_type::priv::temp_internal_cached_name_): New data
	member.
	(function_type::get_cached_name): Cache the internal name after
	the function type is canonicalized.  Make sure internal name and
	non-internal name are cached separately.
	(class_or_union::find_anonymous_data_member): Look for the anonymous
	data member by looking at its non-internal name.
	({class, union}_decl::get_pretty_representation): Use something like "class
	__anonymous_{union,struct}__" for all anonymous classes, so that they can
	all be compared against each other during type canonicalization.
	(type_has_sub_type_changes): Use non-internal pretty
	representation.
	(hash_type_or_decl, function_decl_is_less_than:): Use internal
	pretty representation for comparison here.
	* src/abg-reader.cc (read_context::maybe_canonicalize_type): Don't
	early canonicalize array types.
	* src/abg-writer.cc (annotate): Use non-internal pretty
	representation.
	* tests/data/test-diff-filter/test-PR27995-report-0.txt: New
	reference report.
	* tests/data/test-diff-filter/test-PR27995.abi: New test input
	abixml file.
	* tests/data/Makefile.am: Add test-PR27995.abi,
	test-PR27995-report-0.txt to the source distribution.
	* tests/data/test-annotate/libtest23.so.abi: Adjust.
	* tests/data/test-diff-dwarf/test6-report.txt: Adjust.
	* tests/data/test-diff-filter/test31-pr18535-libstdc++-report-0.txt: Adjust.
	* tests/data/test-diff-filter/test31-pr18535-libstdc++-report-1.txt: Adjust.
	* tests/data/test-diff-filter/test41-report-0.txt: Adjust.
	* tests/data/test-diff-filter/test43-decl-only-def-change-leaf-report-0.txt: Adjust.
	* tests/data/test-diff-filter/test8-report.txt: Adjust.
	* tests/data/test-diff-pkg/libICE-1.0.6-1.el6.x86_64.rpm--libICE-1.0.9-2.el7.x86_64.rpm-report-0.txt:
	Adjust.
	* tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-0.txt:
	Adjust.
	* tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-2.txt:
	Adjust.
	* tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-3.txt:
	Adjust.
	* tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt:
	Adjust.
	* tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-1.txt:
	Adjust.
	* tests/data/test-diff-suppr/test39-opaque-type-report-0.txt: Adjust.
	* tests/data/test-read-dwarf/PR22015-libboost_iostreams.so.abi: Adjust.
	* tests/data/test-read-dwarf/PR22122-libftdc.so.abi: Adjust.
	* tests/data/test-read-dwarf/libtest23.so.abi: Adjust.
	* tests/data/test-read-dwarf/test-libandroid.so.abi: Adjust.
	* tests/data/test-read-dwarf/test11-pr18828.so.abi: Adjust.
	* tests/data/test-read-dwarf/test12-pr18844.so.abi: Adjust.
	* tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Adjust.
	* tests/test-diff-filter.cc (in_out_specs): Add the
	test-PR27995.abi to the test harness.
	* tools/abidiff.cc (options::do_debug): New data member.
	(options::options): Initialize it.
	(parse_command_line): Parse --debug.
	(main): Activate self comparison debug if the user provided
	--debug.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2021-08-11 17:38:14 +02:00

958 lines
36 KiB
C++

// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2020 Red Hat, Inc.
//
// Author: Dodji Seketeli
/// @file
///
/// This program runs a diff between input ELF files containing DWARF
/// debugging information and compares the resulting report with a
/// reference report. If the resulting report is different from the
/// reference report, the test has failed. Note that the comparison
/// is done using the abidiff command line comparison tool.
///
/// The set of input files and reference reports to consider should be
/// present in the source distribution.
#include <sys/wait.h>
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include "abg-workers.h"
#include "abg-tools-utils.h"
#include "test-utils.h"
using std::string;
using std::cerr;
/// This is an aggregate that specifies where a test shall get its
/// input from and where it shall write its ouput to.
struct InOutSpec
{
const char* in_elfv0_path;
const char* in_elfv1_path;
const char* abidiff_options;
const char* in_report_path;
const char* out_report_path;
}; // end struct InOutSpec;
InOutSpec in_out_specs[] =
{
{
"data/test-diff-filter/test0-v0.o",
"data/test-diff-filter/test0-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test0-report.txt",
"output/test-diff-filter/test0-report.txt",
},
{
"data/test-diff-filter/test0-v0.o",
"data/test-diff-filter/test0-v1.o",
"--no-default-suppression --harmless --no-linkage-name "
"--no-show-locs --no-redundant",
"data/test-diff-filter/test01-report.txt",
"output/test-diff-filter/test01-report.txt",
},
{
"data/test-diff-filter/test1-v0.o",
"data/test-diff-filter/test1-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test1-report.txt",
"output/test-diff-filter/test1-report.txt",
},
{
"data/test-diff-filter/test2-v0.o",
"data/test-diff-filter/test2-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test2-report.txt",
"output/test-diff-filter/test2-report.txt",
},
{
"data/test-diff-filter/test3-v0.o",
"data/test-diff-filter/test3-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test3-report.txt",
"output/test-diff-filter/test3-report.txt",
},
{
"data/test-diff-filter/test4-v0.o",
"data/test-diff-filter/test4-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test4-report.txt",
"output/test-diff-filter/test4-report.txt",
},
{
"data/test-diff-filter/test5-v0.o",
"data/test-diff-filter/test5-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test5-report.txt",
"output/test-diff-filter/test5-report.txt",
},
{
"data/test-diff-filter/test6-v0.o",
"data/test-diff-filter/test6-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test6-report.txt",
"output/test-diff-filter/test6-report.txt",
},
{
"data/test-diff-filter/test7-v0.o",
"data/test-diff-filter/test7-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test7-report.txt",
"output/test-diff-filter/test7-report.txt",
},
{
"data/test-diff-filter/test8-v0.o",
"data/test-diff-filter/test8-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test8-report.txt",
"output/test-diff-filter/test8-report.txt",
},
{
"data/test-diff-filter/test9-v0.o",
"data/test-diff-filter/test9-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test9-report.txt",
"output/test-diff-filter/test9-report.txt",
},
{
"data/test-diff-filter/test10-v0.o",
"data/test-diff-filter/test10-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test10-report.txt",
"output/test-diff-filter/test10-report.txt",
},
{
"data/test-diff-filter/test11-v0.o",
"data/test-diff-filter/test11-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test11-report.txt",
"output/test-diff-filter/test11-report.txt",
},
{
"data/test-diff-filter/test12-v0.o",
"data/test-diff-filter/test12-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test12-report.txt",
"output/test-diff-filter/test12-report.txt",
},
{
"data/test-diff-filter/test13-v0.o",
"data/test-diff-filter/test13-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test13-report.txt",
"output/test-diff-filter/test13-report.txt",
},
{
"data/test-diff-filter/test14-v0.o",
"data/test-diff-filter/test14-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test14-0-report.txt",
"output/test-diff-filter/test14-0-report.txt",
},
{
"data/test-diff-filter/test14-v0.o",
"data/test-diff-filter/test14-v1.o",
"--no-default-suppression --no-show-locs --redundant",
"data/test-diff-filter/test14-1-report.txt",
"output/test-diff-filter/test14-1-report.txt",
},
{
"data/test-diff-filter/test15-v0.o",
"data/test-diff-filter/test15-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test15-0-report.txt",
"output/test-diff-filter/test15-0-report.txt",
},
{
"data/test-diff-filter/test15-v0.o",
"data/test-diff-filter/test15-v1.o",
"--no-default-suppression --no-show-locs --redundant",
"data/test-diff-filter/test15-1-report.txt",
"output/test-diff-filter/test15-1-report.txt",
},
{
"data/test-diff-filter/test16-v0.o",
"data/test-diff-filter/test16-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test16-report.txt",
"output/test-diff-filter/test16-report.txt",
},
{
"data/test-diff-filter/test16-v0.o",
"data/test-diff-filter/test16-v1.o",
"--no-default-suppression --no-show-locs --redundant",
"data/test-diff-filter/test16-report-2.txt",
"output/test-diff-filter/test16-report-2.txt",
},
{
"data/test-diff-filter/test17-v0.o",
"data/test-diff-filter/test17-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test17-0-report.txt",
"output/test-diff-filter/test17-0-report.txt",
},
{
"data/test-diff-filter/test17-v0.o",
"data/test-diff-filter/test17-v1.o",
"--no-default-suppression --no-show-locs --redundant",
"data/test-diff-filter/test17-1-report.txt",
"output/test-diff-filter/test17-1-report.txt",
},
{
"data/test-diff-filter/test18-v0.o",
"data/test-diff-filter/test18-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test18-report.txt",
"output/test-diff-filter/test18-report.txt",
},
{
"data/test-diff-filter/test19-enum-v0.o",
"data/test-diff-filter/test19-enum-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test19-enum-report-0.txt",
"output/test-diff-filter/test19-enum-report-0.txt",
},
{
"data/test-diff-filter/test19-enum-v0.o",
"data/test-diff-filter/test19-enum-v1.o",
"--no-default-suppression --no-show-locs --harmless",
"data/test-diff-filter/test19-enum-report-1.txt",
"output/test-diff-filter/test19-enum-report-1.txt",
},
{
"data/test-diff-filter/test20-inline-v0.o",
"data/test-diff-filter/test20-inline-v1.o",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test20-inline-report-0.txt",
"output/test-diff-filter/test20-inline-report-0.txt",
},
{
"data/test-diff-filter/test20-inline-v0.o",
"data/test-diff-filter/test20-inline-v1.o",
"--no-default-suppression --no-show-locs --harmless",
"data/test-diff-filter/test20-inline-report-1.txt",
"output/test-diff-filter/test20-inline-report-1.txt",
},
{
"data/test-diff-filter/libtest21-compatible-vars-v0.so",
"data/test-diff-filter/libtest21-compatible-vars-v1.so",
"--no-default-suppression --no-show-locs --harmless",
"data/test-diff-filter/test21-compatible-vars-report-0.txt",
"output/test-diff-filter/test21-compatible-vars-report-0.txt",
},
{
"data/test-diff-filter/libtest21-compatible-vars-v0.so",
"data/test-diff-filter/libtest21-compatible-vars-v1.so",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test21-compatible-vars-report-1.txt",
"output/test-diff-filter/test21-compatible-vars-report-1.txt",
},
{
"data/test-diff-filter/libtest22-compatible-fns-v0.so",
"data/test-diff-filter/libtest22-compatible-fns-v1.so",
"--no-default-suppression --no-show-locs --harmless",
"data/test-diff-filter/test22-compatible-fns-report-0.txt",
"output/test-diff-filter/test22-compatible-fns-report-0.txt",
},
{
"data/test-diff-filter/libtest22-compatible-fns-v0.so",
"data/test-diff-filter/libtest22-compatible-fns-v1.so",
"--no-default-suppression --no-show-locs --no-redundant",
"data/test-diff-filter/test22-compatible-fns-report-1.txt",
"output/test-diff-filter/test22-compatible-fns-report-1.txt",
},
{
"data/test-diff-filter/libtest23-redundant-fn-parm-change-v0.so",
"data/test-diff-filter/libtest23-redundant-fn-parm-change-v1.so",
"--no-default-suppression --no-show-locs",
"data/test-diff-filter/test23-redundant-fn-parm-change-report-0.txt ",
"output/test-diff-filter/test23-redundant-fn-parm-change-report-0.txt ",
},
{
"data/test-diff-filter/libtest24-compatible-vars-v0.so",
"data/test-diff-filter/libtest24-compatible-vars-v1.so",
"--no-default-suppression --no-show-locs",
"data/test-diff-filter/test24-compatible-vars-report-0.txt ",
"output/test-diff-filter/test24-compatible-vars-report-0.txt ",
},
{
"data/test-diff-filter/libtest24-compatible-vars-v0.so",
"data/test-diff-filter/libtest24-compatible-vars-v1.so",
"--no-default-suppression --no-show-locs --harmless",
"data/test-diff-filter/test24-compatible-vars-report-1.txt ",
"output/test-diff-filter/test24-compatible-vars-report-1.txt ",
},
{
"data/test-diff-filter/libtest25-cyclic-type-v0.so",
"data/test-diff-filter/libtest25-cyclic-type-v1.so",
"--no-default-suppression --no-show-locs",
"data/test-diff-filter/test25-cyclic-type-report-0.txt ",
"output/test-diff-filter/test25-cyclic-type-report-0.txt "
},
{
"data/test-diff-filter/libtest25-cyclic-type-v0.so",
"data/test-diff-filter/libtest25-cyclic-type-v1.so",
"--no-default-suppression --no-show-locs --redundant",
"data/test-diff-filter/test25-cyclic-type-report-1.txt ",
"output/test-diff-filter/test25-cyclic-type-report-1.txt "
},
{
"data/test-diff-filter/libtest26-qualified-redundant-node-v0.so",
"data/test-diff-filter/libtest26-qualified-redundant-node-v1.so",
"--no-default-suppression --no-show-locs",
"data/test-diff-filter/test26-qualified-redundant-node-report-0.txt",
"output/test-diff-filter/test26-qualified-redundant-node-report-0.txt"
},
{
"data/test-diff-filter/libtest26-qualified-redundant-node-v0.so",
"data/test-diff-filter/libtest26-qualified-redundant-node-v1.so",
"--no-default-suppression --no-show-locs --redundant",
"data/test-diff-filter/test26-qualified-redundant-node-report-1.txt",
"output/test-diff-filter/test26-qualified-redundant-node-report-1.txt"
},
{
"data/test-diff-filter/libtest27-redundant-and-filtered-children-nodes-v0.so",
"data/test-diff-filter/libtest27-redundant-and-filtered-children-nodes-v1.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test27-redundant-and-filtered-children-nodes-report-0.txt",
"output/test-diff-filter/test27-redundant-and-filtered-children-nodes-report-0.txt"
},
{
"data/test-diff-filter/libtest27-redundant-and-filtered-children-nodes-v0.so",
"data/test-diff-filter/libtest27-redundant-and-filtered-children-nodes-v1.so",
"--no-default-suppression --no-linkage-name --no-show-locs --redundant",
"data/test-diff-filter/test27-redundant-and-filtered-children-nodes-report-1.txt",
"output/test-diff-filter/test27-redundant-and-filtered-children-nodes-report-1.txt"
},
{
"data/test-diff-filter/libtest27-redundant-and-filtered-children-nodes-v0.so",
"data/test-diff-filter/libtest27-redundant-and-filtered-children-nodes-v1.so",
"--no-default-suppression --no-linkage-name --redundant --no-show-locs --harmless",
"data/test-diff-filter/test27-redundant-and-filtered-children-nodes-report-2.txt",
"output/test-diff-filter/test27-redundant-and-filtered-children-nodes-report-2.txt"
},
{
"data/test-diff-filter/libtest28-redundant-and-filtered-children-nodes-v0.so",
"data/test-diff-filter/libtest28-redundant-and-filtered-children-nodes-v1.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test28-redundant-and-filtered-children-nodes-report-0.txt",
"output/test-diff-filter/test28-redundant-and-filtered-children-nodes-report-0.txt",
},
{
"data/test-diff-filter/libtest28-redundant-and-filtered-children-nodes-v0.so",
"data/test-diff-filter/libtest28-redundant-and-filtered-children-nodes-v1.so",
"--no-default-suppression --no-linkage-name --redundant --no-show-locs --harmless",
"data/test-diff-filter/test28-redundant-and-filtered-children-nodes-report-1.txt",
"output/test-diff-filter/test28-redundant-and-filtered-children-nodes-report-1.txt",
},
{
"data/test-diff-filter/test29-finer-redundancy-marking-v0.o",
"data/test-diff-filter/test29-finer-redundancy-marking-v1.o",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test29-finer-redundancy-marking-report-0.txt",
"output/test-diff-filter/test29-finer-redundancy-marking-report-0.txt",
},
{
"data/test-diff-filter/test30-pr18904-rvalueref-liba.so",
"data/test-diff-filter/test30-pr18904-rvalueref-libb.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test30-pr18904-rvalueref-report0.txt",
"output/test-diff-filter/test30-pr18904-rvalueref-report0.txt",
},
{ // Just like the previous test, but emit loc info.
"data/test-diff-filter/test30-pr18904-rvalueref-liba.so",
"data/test-diff-filter/test30-pr18904-rvalueref-libb.so",
"--no-default-suppression --no-linkage-name --no-redundant",
"data/test-diff-filter/test30-pr18904-rvalueref-report1.txt",
"output/test-diff-filter/test30-pr18904-rvalueref-report1.txt",
},
{ // Just like the previous test, but emit sizes in hex and bytes
"data/test-diff-filter/test30-pr18904-rvalueref-liba.so",
"data/test-diff-filter/test30-pr18904-rvalueref-libb.so",
"--no-default-suppression --no-linkage-name --no-redundant "
"--show-hex --show-bytes",
"data/test-diff-filter/test30-pr18904-rvalueref-report2.txt",
"output/test-diff-filter/test30-pr18904-rvalueref-report2.txt",
},
{
"data/test-diff-filter/test31-pr18535-libstdc++-4.8.3.so",
"data/test-diff-filter/test31-pr18535-libstdc++-4.9.2.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test31-pr18535-libstdc++-report-0.txt",
"output/test-diff-filter/test31-pr18535-libstdc++-report-0.txt",
},
{ // Just like the previous test, but emit loc info.
"data/test-diff-filter/test31-pr18535-libstdc++-4.8.3.so",
"data/test-diff-filter/test31-pr18535-libstdc++-4.9.2.so",
"--no-default-suppression --no-linkage-name --no-redundant",
"data/test-diff-filter/test31-pr18535-libstdc++-report-1.txt",
"output/test-diff-filter/test31-pr18535-libstdc++-report-1.txt",
},
{
"data/test-diff-filter/libtest32-struct-change-v0.so",
"data/test-diff-filter/libtest32-struct-change-v1.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test32-ppc64le-struct-change-report0.txt",
"output/test-diff-filter/test32-ppc64le-struct-change-report0.txt",
},
{
"data/test-diff-filter/test33-libelf.so.0.8.13-gcc",
"data/test-diff-filter/test33-libelf.so.0.8.13-intel16.0.3",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test33-report-0.txt",
"output/test-diff-filter/test33-report-0.txt",
},
{
"data/test-diff-filter/test34-libjemalloc.so.2-gcc-6.1.0",
"data/test-diff-filter/test34-libjemalloc.so.2-intel-16.0.3",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
"data/test-diff-filter/test34-report-0.txt",
"output/test-diff-filter/test34-report-0.txt",
},
{
"data/test-diff-filter/test30-pr18904-rvalueref-liba.so",
"data/test-diff-filter/test30-pr18904-rvalueref-libb.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant --no-added-syms",
"data/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt",
"output/test-diff-filter/test35-pr18754-no-added-syms-report-0.txt",
},
{
"data/test-diff-filter/test30-pr18904-rvalueref-liba.so",
"data/test-diff-filter/test30-pr18904-rvalueref-libb.so",
"--no-default-suppression --no-linkage-name --no-show-locs --no-redundant --deleted-fns --changed-vars --no-added-syms",
"data/test-diff-filter/test35-pr18754-no-added-syms-report-1.txt",
"output/test-diff-filter/test35-pr18754-no-added-syms-report-1.txt",
},
{
"data/test-diff-filter/libtest36-v0.so",
"data/test-diff-filter/libtest36-v1.so",
"--no-default-suppression --no-linkage-name",
"data/test-diff-filter/test36-report-0.txt",
"output/test-diff-filter/test36-report-0.txt",
},
{
"data/test-diff-filter/libtest37-v0.so",
"data/test-diff-filter/libtest37-v1.so",
"--no-default-suppression --no-linkage-name",
"data/test-diff-filter/test37-report-0.txt",
"output/test-diff-filter/test37-report-0.txt",
},
{
"data/test-diff-filter/test38/test38-v0",
"data/test-diff-filter/test38/test38-v1",
"--no-default-suppression --no-linkage-name",
"data/test-diff-filter/test38/test38-report-0.txt",
"output/test-diff-filter/test38/test38-report-0.txt",
},
{
"data/test-diff-filter/test39/test39-v0",
"data/test-diff-filter/test39/test39-v1",
"--no-default-suppression --no-linkage-name",
"data/test-diff-filter/test39/test39-report-0.txt",
"output/test-diff-filter/test39/test39-report-0.txt",
},
{
"data/test-diff-filter/libtest40-v0.so",
"data/test-diff-filter/libtest40-v1.so",
"--no-default-suppression --no-linkage-name",
"data/test-diff-filter/test40-report-0.txt",
"output/test-diff-filter/test40-report-0.txt",
},
{
"data/test-diff-filter/test41-PR21486-abg-writer.gcc.o",
"data/test-diff-filter/test41-PR21486-abg-writer.llvm.o",
"--no-default-suppression",
"data/test-diff-filter/test41-report-0.txt",
"output/test-diff-filter/test41-report-0.txt",
},
{
"data/test-diff-filter/libtest42-leaf-report-v0.so",
"data/test-diff-filter/libtest42-leaf-report-v1.so",
"--no-default-suppression --leaf-changes-only --impacted-interfaces",
"data/test-diff-filter/test42-leaf-report-output-0.txt",
"output/test-diff-filter/test42-leaf-report-output-0.txt",
},
{
"data/test-diff-filter/libtest43-decl-only-def-change-leaf-report-v0.so",
"data/test-diff-filter/libtest43-decl-only-def-change-leaf-report-v1.so",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test43-decl-only-def-change-leaf-report-0.txt",
"output/test-diff-filter/test43-decl-only-def-change-leaf-report-0.txt",
},
{
"data/test-diff-filter/libtest44-anonymous-data-member-v0.so",
"data/test-diff-filter/libtest44-anonymous-data-member-v1.so",
"--no-default-suppression",
"data/test-diff-filter/test44-anonymous-data-member-report-0.txt",
"output/test-diff-filter/test44-anonymous-data-member-report-0.txt",
},
{
"data/test-diff-filter/libtest44-anonymous-data-member-v0.so",
"data/test-diff-filter/libtest44-anonymous-data-member-v1.so",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test44-anonymous-data-member-report-1.txt",
"output/test-diff-filter/test44-anonymous-data-member-report-1.txt",
},
{
"data/test-diff-filter/libtest45-basic-type-change-v0.so",
"data/test-diff-filter/libtest45-basic-type-change-v1.so",
"--no-default-suppression",
"data/test-diff-filter/libtest45-basic-type-change-report-0.txt",
"output/test-diff-filter/libtest45-basic-type-change-report-0.txt",
},
{
"data/test-diff-filter/libtest45-basic-type-change-v0.so",
"data/test-diff-filter/libtest45-basic-type-change-v1.so",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/libtest45-basic-type-change-report-1.txt",
"output/test-diff-filter/libtest45-basic-type-change-report-1.txt",
},
{
"data/test-diff-filter/test46-fn-return-qual-change-v0.o",
"data/test-diff-filter/test46-fn-return-qual-change-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test46-fn-return-qual-change-report-0.txt",
"output/test-diff-filter/test46-fn-return-qual-change-report-0.txt",
},
{
"data/test-diff-filter/test47-filter-void-ptr-change-v0.o",
"data/test-diff-filter/test47-filter-void-ptr-change-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test47-filter-void-ptr-change-report-0.txt",
"output/test-diff-filter/test47-filter-void-ptr-change-report-0.txt",
},
{
"data/test-diff-filter/PR24430-fold-qualified-array-clang",
"data/test-diff-filter/PR24430-fold-qualified-array-gcc",
"--no-default-suppression",
"data/test-diff-filter/PR24430-fold-qualified-array-report-0.txt",
"output/test-diff-filter/PR24430-fold-qualified-array-report-0.txt",
},
{
"data/test-diff-filter/test-PR24731-v0.o ",
"data/test-diff-filter/test-PR24731-v1.o ",
"--no-default-suppression",
"data/test-diff-filter/test-PR24731-report-0.txt",
"output/test-diff-filter/test-PR24731-report-0.txt",
},
{
"data/test-diff-filter/test-PR24731-v0.o ",
"data/test-diff-filter/test-PR24731-v1.o ",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR24731-report-1.txt",
"output/test-diff-filter/test-PR24731-report-1.txt",
},
{
"data/test-diff-filter/PR24787-libone.so",
"data/test-diff-filter/PR24787-libtwo.so",
"--no-default-suppression",
"data/test-diff-filter/PR24787-report-0.txt",
"output/test-diff-filter/PR24787-report-0.txt",
},
{
"data/test-diff-filter/test-PR25661-1-v0.o",
"data/test-diff-filter/test-PR25661-1-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-1-report-1.txt",
"output/test-diff-filter/test-PR25661-1-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-1-v0.o",
"data/test-diff-filter/test-PR25661-1-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-1-report-2.txt",
"output/test-diff-filter/test-PR25661-1-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-1-v0.o",
"data/test-diff-filter/test-PR25661-1-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-1-report-3.txt",
"output/test-diff-filter/test-PR25661-1-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-1-v0.o",
"data/test-diff-filter/test-PR25661-1-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-1-report-4.txt",
"output/test-diff-filter/test-PR25661-1-report-4.txt",
},
{
"data/test-diff-filter/test-PR25661-2-v0.o",
"data/test-diff-filter/test-PR25661-2-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-2-report-1.txt",
"output/test-diff-filter/test-PR25661-2-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-2-v0.o",
"data/test-diff-filter/test-PR25661-2-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-2-report-2.txt",
"output/test-diff-filter/test-PR25661-2-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-2-v0.o",
"data/test-diff-filter/test-PR25661-2-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-2-report-3.txt",
"output/test-diff-filter/test-PR25661-2-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-2-v0.o",
"data/test-diff-filter/test-PR25661-2-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-2-report-4.txt",
"output/test-diff-filter/test-PR25661-2-report-4.txt",
},
{
"data/test-diff-filter/test-PR25661-3-v0.o",
"data/test-diff-filter/test-PR25661-3-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-3-report-1.txt",
"output/test-diff-filter/test-PR25661-3-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-3-v0.o",
"data/test-diff-filter/test-PR25661-3-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-3-report-2.txt",
"output/test-diff-filter/test-PR25661-3-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-3-v0.o",
"data/test-diff-filter/test-PR25661-3-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-3-report-3.txt",
"output/test-diff-filter/test-PR25661-3-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-3-v0.o",
"data/test-diff-filter/test-PR25661-3-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-3-report-4.txt",
"output/test-diff-filter/test-PR25661-3-report-4.txt",
},
{
"data/test-diff-filter/test-PR25661-4-v0.o",
"data/test-diff-filter/test-PR25661-4-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-4-report-1.txt",
"output/test-diff-filter/test-PR25661-4-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-4-v0.o",
"data/test-diff-filter/test-PR25661-4-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-4-report-2.txt",
"output/test-diff-filter/test-PR25661-4-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-4-v0.o",
"data/test-diff-filter/test-PR25661-4-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-4-report-3.txt",
"output/test-diff-filter/test-PR25661-4-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-4-v0.o",
"data/test-diff-filter/test-PR25661-4-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-4-report-4.txt",
"output/test-diff-filter/test-PR25661-4-report-4.txt",
},
{
"data/test-diff-filter/test-PR25661-5-v0.o",
"data/test-diff-filter/test-PR25661-5-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-5-report-1.txt",
"output/test-diff-filter/test-PR25661-5-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-5-v0.o",
"data/test-diff-filter/test-PR25661-5-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-5-report-2.txt",
"output/test-diff-filter/test-PR25661-5-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-5-v0.o",
"data/test-diff-filter/test-PR25661-5-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-5-report-3.txt",
"output/test-diff-filter/test-PR25661-5-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-5-v0.o",
"data/test-diff-filter/test-PR25661-5-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-5-report-4.txt",
"output/test-diff-filter/test-PR25661-5-report-4.txt",
},
{
"data/test-diff-filter/test-PR25661-6-v0.o",
"data/test-diff-filter/test-PR25661-6-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-6-report-1.txt",
"output/test-diff-filter/test-PR25661-6-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-6-v0.o",
"data/test-diff-filter/test-PR25661-6-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-6-report-2.txt",
"output/test-diff-filter/test-PR25661-6-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-6-v0.o",
"data/test-diff-filter/test-PR25661-6-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-6-report-3.txt",
"output/test-diff-filter/test-PR25661-6-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-6-v0.o",
"data/test-diff-filter/test-PR25661-6-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-6-report-4.txt",
"output/test-diff-filter/test-PR25661-6-report-4.txt",
},
{
"data/test-diff-filter/test-PR25661-7-v0.o",
"data/test-diff-filter/test-PR25661-7-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR25661-7-report-1.txt",
"output/test-diff-filter/test-PR25661-7-report-1.txt",
},
{
"data/test-diff-filter/test-PR25661-7-v0.o",
"data/test-diff-filter/test-PR25661-7-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR25661-7-report-2.txt",
"output/test-diff-filter/test-PR25661-7-report-2.txt",
},
{
"data/test-diff-filter/test-PR25661-7-v0.o",
"data/test-diff-filter/test-PR25661-7-v1.o",
"--no-default-suppression --harmless",
"data/test-diff-filter/test-PR25661-7-report-3.txt",
"output/test-diff-filter/test-PR25661-7-report-3.txt",
},
{
"data/test-diff-filter/test-PR25661-7-v0.o",
"data/test-diff-filter/test-PR25661-7-v1.o",
"--no-default-suppression --harmless --leaf-changes-only",
"data/test-diff-filter/test-PR25661-7-report-4.txt",
"output/test-diff-filter/test-PR25661-7-report-4.txt",
},
{
"data/test-diff-filter/test-PR26309-v0.o",
"data/test-diff-filter/test-PR26309-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR26309-report-0.txt",
"output/test-diff-filter/test-PR26309-report-0.txt",
},
{
"data/test-diff-filter/test-PR26739-v0.o",
"data/test-diff-filter/test-PR26739-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR26739-report-0.txt",
"output/test-diff-filter/test-PR26739-report-0.txt",
},
{
"data/test-diff-filter/test-PR26739-2-v0.o",
"data/test-diff-filter/test-PR26739-2-v1.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR26739-2-report-0.txt",
"output/test-diff-filter/test-PR26739-2-report-0.txt",
},
{
"data/test-diff-filter/test-PR26684-dwarf4.o",
"data/test-diff-filter/test-PR26684-dwarf5.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR26684-report-0.txt",
"output/test-diff-filter/test-PR26684-report-0.txt",
},
{
"data/test-diff-filter/test-PR27331-v0.o",
"data/test-diff-filter/test-PR27331-v1.o",
"--no-default-suppression --leaf-changes-only",
"data/test-diff-filter/test-PR27331-report-0.txt",
"output/test-diff-filter/test-PR27331-report-0.txt",
},
{
"data/test-diff-filter/test-PR27569-v0.abi",
"data/test-diff-filter/test-PR27569-v1.abi",
"--no-default-suppression",
"data/test-diff-filter/test-PR27569-report-0.txt",
"output/test-diff-filter/test-PR27569-report-0.txt",
},
{
"data/test-diff-filter/test-PR27598-v0.o",
"data/test-diff-filter/test-PR27598-v0.o",
"--no-default-suppression",
"data/test-diff-filter/test-PR27598-report-0.txt",
"output/test-diff-filter/test-PR27598-report-0.txt",
},
{
"data/test-diff-filter/test-PR27995.abi",
"data/test-diff-filter/test-PR27995.abi",
"--no-default-suppression",
"data/test-diff-filter/test-PR27995-report-0.txt",
"output/test-diff-filter/test-PR27995-report-0.txt",
},
// This should be the last entry
{NULL, NULL, NULL, NULL, NULL}
};
/// A task which launches abidiff on the binaries passed to the
/// constructor of the task. The test also launches gnu diff on the
/// result of the abidiff to compare it against a reference abidiff
/// result.
struct test_task : public abigail::workers::task
{
InOutSpec spec;
bool is_ok;
string diff_cmd;
string error_message;
test_task(const InOutSpec& s)
: spec(s),
is_ok(true)
{}
/// This virtual function overload actually performs the job of the
/// task.
///
/// It actually launches abidiff on the binaries passed to the
/// constructor of the task. It also launches gnu diff on the
/// result of the abidiff to compare it against a reference abidiff
/// result.
virtual void
perform()
{
using abigail::tests::get_src_dir;
using abigail::tests::get_build_dir;
using abigail::tools_utils::ensure_parent_dir_created;
using abigail::tools_utils::abidiff_status;
string in_elfv0_path, in_elfv1_path,
abidiff_options, abidiff, cmd,
ref_diff_report_path, out_diff_report_path;
in_elfv0_path = string(get_src_dir()) + "/tests/" + spec.in_elfv0_path;
in_elfv1_path = string(get_src_dir()) + "/tests/" + spec.in_elfv1_path;
abidiff_options = spec.abidiff_options;
ref_diff_report_path =
string(get_src_dir()) + "/tests/" + spec.in_report_path;
out_diff_report_path =
string(get_build_dir()) + "/tests/" + spec.out_report_path;
if (!ensure_parent_dir_created(out_diff_report_path))
{
error_message = string("could not create parent directory for ")
+ out_diff_report_path;
is_ok = false;
return;
}
abidiff = string(get_build_dir()) + "/tools/abidiff";
abidiff += " " + abidiff_options;
cmd = abidiff + " " + in_elfv0_path + " " + in_elfv1_path;
cmd += " > " + out_diff_report_path;
bool abidiff_ok = true;
int code = system(cmd.c_str());
if (!WIFEXITED(code))
abidiff_ok = false;
else
{
abidiff_status status =
static_cast<abidiff_status>(WEXITSTATUS(code));
if (abigail::tools_utils::abidiff_status_has_error(status))
abidiff_ok = false;
}
if (abidiff_ok)
{
cmd = "diff -u " + ref_diff_report_path
+ " " + out_diff_report_path;
string cmd_no_out = cmd + " > /dev/null";
if (system(cmd_no_out.c_str()))
{
is_ok = false;
diff_cmd = cmd;
}
}
else
is_ok = false;
}
}; //end struct test_task.
/// A convenience typedef for shared
typedef shared_ptr<test_task> test_task_sptr;
int
main()
{
using std::vector;
using std::dynamic_pointer_cast;
using abigail::workers::queue;
using abigail::workers::task;
using abigail::workers::task_sptr;
using abigail::workers::get_number_of_threads;
/// Create a task queue. The max number of worker threads of the
/// queue is the number of the concurrent threads supported by the
/// processor of the machine this code runs on.
const size_t num_tests = sizeof(in_out_specs) / sizeof (InOutSpec) - 1;
size_t num_workers = std::min(get_number_of_threads(), num_tests);
queue task_queue(num_workers);
bool is_ok = true;
for (InOutSpec* s = in_out_specs; s->in_elfv0_path; ++s)
{
test_task_sptr t(new test_task(*s));
ABG_ASSERT(task_queue.schedule_task(t));
}
/// Wait for all worker threads to finish their job, and wind down.
task_queue.wait_for_workers_to_complete();
// Now walk the results and print whatever error messages need to be
// printed.
const vector<task_sptr>& completed_tasks =
task_queue.get_completed_tasks();
ABG_ASSERT(completed_tasks.size() == num_tests);
for (vector<task_sptr>::const_iterator ti = completed_tasks.begin();
ti != completed_tasks.end();
++ti)
{
test_task_sptr t = dynamic_pointer_cast<test_task>(*ti);
if (!t->is_ok)
{
is_ok = false;
if (!t->diff_cmd.empty())
if (system(t->diff_cmd.c_str()) == -1)
cerr << "execution of '" << t->diff_cmd << "' failed\n";
if (!t->error_message.empty())
cerr << t->error_message << '\n';
}
}
return !is_ok;
}