Просмотр исходного кода

scripts/t/200_Dpkg_Shlibs.t: extend test suite to cover symbol patterns functionality

Signed-off-by: Modestas Vainius <modax@debian.org>
Signed-off-by: Raphaël Hertzog <hertzog@debian.org>
Raphaël Hertzog лет назад: 16
Родитель
Сommit
da19cee896

+ 13 - 1
scripts/Makefile.am

@@ -151,7 +151,8 @@ test_cases = \
 
 check_DATA = \
 	$(test_tmpdir)/200_Dpkg_Shlibs/objdump.basictags-amd64 \
-	$(test_tmpdir)/200_Dpkg_Shlibs/objdump.basictags-i386
+	$(test_tmpdir)/200_Dpkg_Shlibs/objdump.basictags-i386 \
+	$(test_tmpdir)/200_Dpkg_Shlibs/objdump.patterns
 
 test_data = \
 	t/200_Dpkg_Shlibs/symbols.fake-1 \
@@ -162,6 +163,9 @@ test_data = \
 	t/200_Dpkg_Shlibs/symbols.include-3 \
 	t/200_Dpkg_Shlibs/basictags.symbols \
 	t/200_Dpkg_Shlibs/basictags.c \
+	t/200_Dpkg_Shlibs/patterns.symbols \
+	t/200_Dpkg_Shlibs/patterns.cpp \
+	t/200_Dpkg_Shlibs/patterns.map \
 	t/200_Dpkg_Shlibs/ld.so.conf \
 	t/200_Dpkg_Shlibs/ld.so.conf_2 \
 	t/200_Dpkg_Shlibs/ld.so.conf.d/normal.conf \
@@ -201,3 +205,11 @@ $(test_tmpdir)/200_Dpkg_Shlibs/objdump.basictags-amd64 $(test_tmpdir)/200_Dpkg_S
 	  sed "s/$(objdump_lib_name)/libbasictags.so.1/g" > $@
 	rm -f $(objdump_lib_name)
 
+$(test_tmpdir)/200_Dpkg_Shlibs/objdump.patterns: $(srcdir)/t/200_Dpkg_Shlibs/patterns.cpp $(srcdir)/t/200_Dpkg_Shlibs/patterns.map
+	$(mkdir_p) $(test_tmpdir)/200_Dpkg_Shlibs
+	$(CXX) $(CXXFLAGS) -shared -fPIC -Wl,-soname -Wl,libpatterns.so.1 \
+	    -Wl,--version-script=$(srcdir)/t/200_Dpkg_Shlibs/patterns.map $< \
+	    -o $(objdump_lib_name)
+	objdump -w -f -p -T -R $(objdump_lib_name) | \
+	  sed "s/$(objdump_lib_name)/libpatterns.so.1/g" > $@
+	rm -f $(objdump_lib_name)

+ 144 - 2
scripts/t/200_Dpkg_Shlibs.t

@@ -13,7 +13,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-use Test::More tests => 65;
+use Test::More tests => 97;
 use Cwd;
 use IO::String;
 
@@ -135,7 +135,7 @@ ok( $sym_file->get_new_symbols($sym_file_old), 'has new symbols' );
 ok( $sym_file_old->get_lost_symbols($sym_file), 'has lost symbols' );
 
 is( $sym_file_old->lookup_symbol('__bss_start@Base', ['libc.so.6']),
-    undef, 'internal symbols are blacklisted');
+    undef, 'internal symbols are blacklisted' );
 
 $sym = $sym_file->lookup_symbol('_errno@GLIBC_2.0', ['libc.so.6'], 1);
 isa_ok($sym, 'Dpkg::Shlibs::Symbol');
@@ -409,3 +409,145 @@ $tmp[1]->{teststruct}{foo} = 3;
 $tmp[1]->{testfield} = 3;
 is ( $sym->{teststruct}{foo}, 2, 'struct changed via sclone()' );
 is ( $sym->{testfield}, 1, 'original field not changed' );
+
+############ Test symbol patterns ###########
+sub load_patterns_obj {
+    $obj = Dpkg::Shlibs::Objdump::Object->new();
+    open $objdump, '<', "$tmpdir/objdump.patterns"
+	or die "$tmpdir/objdump.patterns: $!";
+    $obj->_parse($objdump);
+    close $objdump;
+    return $obj;
+}
+
+sub load_patterns_symbols {
+    $sym_file = Dpkg::Shlibs::SymbolFile->new(file => "$datadir/patterns.symbols");
+    return $sym_file;
+}
+
+load_patterns_obj();
+$sym_file_dup = load_patterns_symbols();
+load_patterns_symbols();
+
+save_load_test($sym_file, 'save -> load test of patterns template', template_mode => 1);
+
+isnt( $sym_file->get_soname_patterns('libpatterns.so.1') , 0,
+    "patterns.symbols has patterns" );
+
+$sym_file->merge_symbols($obj, '100.MISSING');
+
+@tmp = map { $_->get_symbolname() } $sym_file->get_lost_symbols($sym_file_dup);
+is_deeply( \@tmp, [], "no LOST symbols if all patterns matched." );
+@tmp = map { $_->get_symbolname() } $sym_file->get_new_symbols($sym_file_dup);
+is_deeply( \@tmp, [], "no NEW symbols if all patterns matched." );
+
+# Pattern resolution order: aliases (c++, wildcard), generic
+$sym = $sym_file->lookup_symbol('VERSION_1@VERSION_1',['libpatterns.so.1']);
+is ( $sym->{minver}, '1', "specific VERSION_1 symbol" );
+
+$sym = $sym_file->lookup_symbol('_ZN3NSB8Wildcard16wildcard_method1Ev@VERSION_1', ['libpatterns.so.1']);
+is ( $sym->{minver}, '1.method1', "specific symbol prefered over pattern" );
+
+$sym = $sym_file->lookup_symbol('_ZN3NSB8Wildcard16wildcard_method2Ev@VERSION_1', ['libpatterns.so.1']);
+is ( $sym->{minver}, '1.method2', "c++ alias pattern preferred over generic pattern" );
+is ( $sym->get_pattern()->get_symbolname(), 'NSB::Wildcard::wildcard_method2()@VERSION_1' );
+
+$sym = $sym_file->lookup_symbol('_ZN3NSB8WildcardD1Ev@VERSION_1', ['libpatterns.so.1']);
+is ( $sym->{minver}, '1.generic', 'generic (wildcard & c++) pattern covers the rest (destructor)' );
+is ( $sym->get_pattern()->get_symbolname(), '*@VERSION_1' );
+
+# Lookup private pattern
+my @private_symnames = sort qw(
+    _ZN3NSA6ClassA7Private11privmethod1Ei@Base
+    _ZN3NSA6ClassA7Private11privmethod2Ei@Base
+    _ZN3NSA6ClassA7PrivateC1Ev@Base
+    _ZN3NSA6ClassA7PrivateC2Ev@Base
+    _ZN3NSA6ClassA7PrivateD0Ev@Base
+    _ZN3NSA6ClassA7PrivateD1Ev@Base
+    _ZN3NSA6ClassA7PrivateD2Ev@Base
+    _ZTIN3NSA6ClassA7PrivateE@Base
+    _ZTSN3NSA6ClassA7PrivateE@Base
+    _ZTVN3NSA6ClassA7PrivateE@Base
+);
+$sym = $sym_file->create_symbol('(c++|regex|optional)NSA::ClassA::Private(::.*)?@Base 1');
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1']);
+isnt( $pat, undef, 'pattern for private class has been found' );
+is_deeply( [ sort map { $_->get_symbolname() } $pat->get_pattern_matches() ],
+    \@private_symnames, "private pattern matched expected symbols" );
+ok( ($pat->get_pattern_matches())[0]->is_optional(),
+    "private symbol is optional like its pattern" );
+ok( $sym_file->lookup_symbol(($pat->get_pattern_matches())[0]->get_symbolname(), ['libpatterns.so.1']),
+    "lookup_symbol() finds symbols matched by pattern (after merge)"),
+
+# Get rid of a private symbol, it should not be lost
+delete $obj->{dynsyms}{$private_symnames[0]};
+load_patterns_symbols();
+$sym_file->merge_symbols($obj, '100.MISSING');
+
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1']);
+@tmp = map { $_->get_symbolname() } $sym_file->get_lost_symbols($sym_file_dup);
+is_deeply( \@tmp, [], "no LOST symbols when got rid of patterned optional symbol." );
+ok( ! $pat->{deprecated} , "there are still matches, pattern is not deprecated." );
+
+# Get rid of all private symbols, the pattern should be deprecated.
+foreach my $tmp (@private_symnames) {
+    delete $obj->{dynsyms}{$tmp};
+}
+load_patterns_symbols();
+$sym_file->merge_symbols($obj, '100.MISSING');
+
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1'], 1);
+@tmp = $sym_file->get_lost_symbols($sym_file_dup);
+is_deeply( \@tmp, [ ],
+    "All private symbols gone, but pattern is not LOST because it is optional." );
+is( $pat->{deprecated}, '100.MISSING',
+    "All private symbols gone - pattern deprecated." );
+
+# Internal symbols. All covered by the pattern?
+@tmp = grep { $_->get_symbolname() =~ /Internal/ } values %{$sym_file->{objects}{'libpatterns.so.1'}{syms}};
+$sym = $sym_file->create_symbol('(regex|c++)^_Z(T[ISV])?N3NSA6ClassA8Internal.*@Base$ 1.internal'),
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1']);
+is_deeply ([ sort $pat->get_pattern_matches() ], [ sort @tmp ],
+    "Pattern covers all internal symbols");
+is ( $tmp[0]->{minver}, '1.internal' );
+
+# Delete matches of the non-optional pattern
+$sym = $sym_file->create_symbol('(c++)"non-virtual thunk to NSB::ClassD::generate_vt(char const*) const@Base" 1');
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1']);
+isnt( $pat, undef, 'lookup_pattern() finds alias-based pattern' );
+
+is( scalar($pat->get_pattern_matches()), 2, "two matches for the generate_vt pattern" );
+foreach my $tmp ($pat->get_pattern_matches()) {
+    delete $obj->{dynsyms}{$tmp->get_symbolname()};
+}
+load_patterns_symbols();
+$sym_file->merge_symbols($obj, '100.MISSING');
+
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1'], 1);
+@tmp = map { $sym_file->lookup_pattern($_, ['libpatterns.so.1'], 1) }
+             $sym_file->get_lost_symbols($sym_file_dup);
+is_deeply( \@tmp, [ $pat ], "No matches - generate_vt() pattern is LOST." );
+is( $pat->{deprecated}, '100.MISSING',
+    "No matches - generate_vt() pattern is deprecated." );
+
+# Pattern undeprecation when matches are discovered
+load_patterns_obj();
+load_patterns_symbols();
+
+$pat = $sym_file_dup->lookup_pattern($sym, ['libpatterns.so.1']);
+$pat->{deprecated} = '0.1-1';
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1']);
+$pat->{deprecated} = '0.1-1';
+
+$sym_file->merge_symbols($obj, '100.FOUND');
+ok( ! $pat->{deprecated},
+    "Previously deprecated pattern with matches got undeprecated" );
+is( $pat->{minver}, '100.FOUND',
+    "Previously deprecated pattern with matches got minver bumped" );
+@tmp = map { $_->get_symbolspec(1) } $sym_file->get_new_symbols($sym_file_dup);
+is_deeply( \@tmp, [ $pat->get_symbolspec(1) ],
+    "Previously deprecated pattern with matches is NEW. Matches themselves are not NEW." );
+foreach my $sym ($pat->get_pattern_matches()) {
+    ok( ! $sym->{deprecated}, $sym->get_symbolname().": not deprecated" );
+    is( $sym->{minver}, '100.FOUND', $sym->get_symbolname().": version bumped" );
+}

+ 98 - 0
scripts/t/200_Dpkg_Shlibs/patterns.cpp

@@ -0,0 +1,98 @@
+#define EXPORT(x) x {}
+
+namespace NSA
+{
+    class ClassA
+    {
+	private:
+	    class Private
+	    {
+		public:
+		    Private();
+		    virtual ~Private();
+		    void privmethod1(int);
+		    void privmethod2(int);
+	    };
+	    Private* p;
+	    class Internal
+	    {
+		public:
+		    Internal();
+		    virtual ~Internal();
+		    void internal_method1(char);
+		    void internal_method2(char);
+	    };
+	    Internal* i;
+	public:
+	    ClassA();
+	    virtual ~ClassA();
+	    virtual void generate_vt(const char*) const;
+    };
+
+    EXPORT(ClassA::Private::Private());
+    EXPORT(ClassA::Private::~Private());
+    EXPORT(void ClassA::Private::privmethod1(int));
+    EXPORT(void ClassA::Private::privmethod2(int));
+
+    EXPORT(ClassA::Internal::Internal());
+    EXPORT(ClassA::Internal::~Internal());
+    EXPORT(void ClassA::Internal::internal_method1(char));
+    EXPORT(void ClassA::Internal::internal_method2(char));
+
+    EXPORT(ClassA::ClassA());
+    EXPORT(ClassA::~ClassA());
+    EXPORT(void ClassA::generate_vt(const char*) const);
+};
+
+class ClassB
+{
+    public:
+	ClassB();
+	virtual ~ClassB();
+	virtual void generate_vt(const char*) const;
+};
+
+EXPORT(ClassB::ClassB());
+EXPORT(ClassB::~ClassB());
+EXPORT(void ClassB::generate_vt(const char*) const);
+
+class ClassC
+{
+    public:
+	ClassC();
+	virtual ~ClassC();
+	virtual void generate_vt(const char*) const;
+};
+
+EXPORT(ClassC::ClassC());
+EXPORT(ClassC::~ClassC());
+EXPORT(void ClassC::generate_vt(const char*) const);
+
+namespace NSB
+{
+    class ClassD : public NSA::ClassA, public ClassB, public ClassC
+    {
+	public:
+	    ClassD();
+	    virtual ~ClassD();
+	    virtual void generate_vt(const char*) const;
+    };
+
+    EXPORT(ClassD::ClassD());
+    EXPORT(ClassD::~ClassD());
+    EXPORT(void ClassD::generate_vt(const char*) const);
+
+    class Wildcard {
+	public:
+	    Wildcard();
+	    ~Wildcard();
+
+	    void wildcard_method1();
+	    void wildcard_method2();
+    };
+
+    EXPORT(Wildcard::Wildcard());
+    EXPORT(Wildcard::~Wildcard());
+    EXPORT(void Wildcard::wildcard_method1());
+    EXPORT(void Wildcard::wildcard_method2());
+};

+ 4 - 0
scripts/t/200_Dpkg_Shlibs/patterns.map

@@ -0,0 +1,4 @@
+VERSION_1 {
+	global:
+		_ZN3NSB8Wildcard*;
+};

+ 45 - 0
scripts/t/200_Dpkg_Shlibs/patterns.symbols

@@ -0,0 +1,45 @@
+libpatterns.so.1 libpatterns1 #MINVER#
+ (c++)*@VERSION_1 1.generic
+ (c++|regex|optional)NSA::ClassA::Private(::.*)?@Base 1.private
+ (c++)NSB::Wildcard::wildcard_method2()@VERSION_1 1.method2
+ VERSION_1@VERSION_1 1
+ (regex|c++)^_Z(T[ISV])?N3NSA6ClassA8Internal.*@Base$ 1.internal
+ _ZN3NSA6ClassAC1Ev@Base 1
+ _ZN3NSA6ClassAC2Ev@Base 1
+ _ZN3NSA6ClassAD0Ev@Base 1
+ _ZN3NSA6ClassAD1Ev@Base 1
+ _ZN3NSA6ClassAD2Ev@Base 1
+ _ZN3NSB6ClassDC1Ev@Base 1
+ _ZN3NSB6ClassDC2Ev@Base 1
+ _ZN3NSB6ClassDD0Ev@Base 1
+ _ZN3NSB6ClassDD1Ev@Base 1
+ _ZN3NSB6ClassDD2Ev@Base 1
+ _ZN3NSB8Wildcard16wildcard_method1Ev@VERSION_1 1.method1
+ _ZN6ClassBC1Ev@Base 1
+ _ZN6ClassBC2Ev@Base 1
+ _ZN6ClassBD0Ev@Base 1
+ _ZN6ClassBD1Ev@Base 1
+ _ZN6ClassBD2Ev@Base 1
+ _ZN6ClassCC1Ev@Base 1
+ _ZN6ClassCC2Ev@Base 1
+ _ZN6ClassCD0Ev@Base 1
+ _ZN6ClassCD1Ev@Base 1
+ _ZN6ClassCD2Ev@Base 1
+ _ZNK3NSA6ClassA11generate_vtEPKc@Base 1
+ _ZNK3NSB6ClassD11generate_vtEPKc@Base 1
+ _ZNK6ClassB11generate_vtEPKc@Base 1
+ _ZNK6ClassC11generate_vtEPKc@Base 1
+ _ZTI6ClassB@Base 1
+ _ZTI6ClassC@Base 1
+ _ZTIN3NSA6ClassAE@Base 1
+ _ZTIN3NSB6ClassDE@Base 1
+ _ZTS6ClassB@Base 1
+ _ZTS6ClassC@Base 1
+ _ZTSN3NSA6ClassAE@Base 1
+ _ZTSN3NSB6ClassDE@Base 1
+ _ZTV6ClassB@Base 1
+ _ZTV6ClassC@Base 1
+ _ZTVN3NSA6ClassAE@Base 1
+ _ZTVN3NSB6ClassDE@Base 1
+ (c++)"non-virtual thunk to NSB::ClassD::generate_vt(char const*) const@Base" 1
+ (c++)"non-virtual thunk to NSB::ClassD::~ClassD()@Base" 1