glibc/elf/dso-sort-tests-1.def

74 lines
3.4 KiB
Modula-2
Raw Normal View History

elf: Testing infrastructure for ld.so DSO sorting (BZ #17645) This is the first of a 2-part patch set that fixes slow DSO sorting behavior in the dynamic loader, as reported in BZ #17645. In order to facilitate such a large modification to the dynamic loader, this first patch implements a testing framework for validating shared object sorting behavior, to enable comparison between old/new sorting algorithms, and any later enhancements. This testing infrastructure consists of a Python script scripts/dso-ordering-test.py' which takes in a description language, consisting of strings that describe a set of link dependency relations between DSOs, and generates testcase programs and Makefile fragments to automatically test the described situation, for example: a->b->c->d # four objects linked one after another a->[bc]->d;b->c # a depends on b and c, which both depend on d, # b depends on c (b,c linked to object a in fixed order) a->b->c;{+a;%a;-a} # a, b, c serially dependent, main program uses # dlopen/dlsym/dlclose on object a a->b->c;{}!->[abc] # a, b, c serially dependent; multiple tests generated # to test all permutations of a, b, c ordering linked # to main program (Above is just a short description of what the script can do, more documentation is in the script comments.) Two files containing several new tests, elf/dso-sort-tests-[12].def are added, including test scenarios for BZ #15311 and Redhat issue #1162810 [1]. Due to the nature of dynamic loader tests, where the sorting behavior and test output occurs before/after main(), generating testcases to use support/test-driver.c does not suffice to control meaningful timeout for ld.so. Therefore a new utility program 'support/test-run-command', based on test-driver.c/support_test_main.c has been added. This does the same testcase control, but for a program specified through a command-line rather than at the source code level. This utility is used to run the dynamic loader testcases generated by dso-ordering-test.py. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1162810 Signed-off-by: Chung-Lin Tang <cltang@codesourcery.com> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2021-10-21 13:41:21 +00:00
# DSO sorting test descriptions.
# This file is to be processed by ../scripts/dso-ordering-test.py, see usage
# in elf/Makefile for how it is executed.
# We test both dynamic loader sorting algorithms
tunable_option: glibc.rtld.dynamic_sort=1
tunable_option: glibc.rtld.dynamic_sort=2
# Sequence of single dependencies with no cycles.
tst-dso-ordering1: a->b->c
output: c>b>a>{}<a<b<c
# Sequence including 2 dependent DSOs not at the end of the graph.
tst-dso-ordering2: a->b->[cd]->e
output: e>d>c>b>a>{}<a<b<c<d<e
# Complex order with 3 "layers" of full dependencies
tst-dso-ordering3: a->[bc]->[def]->[gh]->i
output: i>h>g>f>e>d>c>b>a>{}<a<b<c<d<e<f<g<h<i
# Sequence including 2 dependent DSOs at the end of the graph.
# Additionally the same dependencies appear in two paths.
tst-dso-ordering4: a->b->[de];a->c->d->e
output: e>d>c>b>a>{}<a<b<c<d<e
# Test that b->c cross link is respected correctly
tst-dso-ordering5: a!->[bc]->d;b->c
output: d>c>b>a>{}<a<b<c<d
# First DSO fully dependent on 4 DSOs, with another DSO at the end of chain.
tst-dso-ordering6: a->[bcde]->f
output: f>e>d>c>b>a>{}<a<b<c<d<e<f
# Sequence including 2 dependent and 3 dependent DSOs, and one of the
# dependent DSOs is dependent on an earlier DSO.
tst-dso-ordering7: a->[bc];b->[cde];e->f
output: f>e>d>c>b>a>{}<a<b<c<d<e<f
# Sequence where the DSO c is unerlinked and calls a function in DSO a which
# is technically a cycle. The main executable depends on the first two DSOs.
# Note: This test has unspecified behavior.
tst-dso-ordering8: a->b->c=>a;{}->[ba]
output: c>b>a>{}<a<b<c
# Generate the permutation of DT_NEEDED order between the main binary and
# all 5 DSOs; all link orders should produce exact same init/fini ordering
tst-dso-ordering9: a->b->c->d->e;{}!->[abcde]
output: e>d>c>b>a>{}<a<b<c<d<e
# Test if init/fini ordering behavior is proper, despite main program with
# an soname that may cause confusion
tst-dso-ordering10: {}->a->b->c;soname({})=c
output: b>a>{}<a<b
# Complex example from Bugzilla #15311, under-linked and with circular
# relocation(dynamic) dependencies. While this is technically unspecified, the
# presumed reasonable practical behavior is for the destructor order to respect
# the static DT_NEEDED links (here this means the a->b->c->d order).
# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based
# dynamic_sort=2 algorithm does, although it is still arguable whether going
# beyond spec to do this is the right thing to do.
# The below expected outputs are what the two algorithms currently produce
# respectively, for regression testing purposes.
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
elf: Fix slow DSO sorting behavior in dynamic loader (BZ #17645) This second patch contains the actual implementation of a new sorting algorithm for shared objects in the dynamic loader, which solves the slow behavior that the current "old" algorithm falls into when the DSO set contains circular dependencies. The new algorithm implemented here is simply depth-first search (DFS) to obtain the Reverse-Post Order (RPO) sequence, a topological sort. A new l_visited:1 bitfield is added to struct link_map to more elegantly facilitate such a search. The DFS algorithm is applied to the input maps[nmap-1] backwards towards maps[0]. This has the effect of a more "shallow" recursion depth in general since the input is in BFS. Also, when combined with the natural order of processing l_initfini[] at each node, this creates a resulting output sorting closer to the intuitive "left-to-right" order in most cases. Another notable implementation adjustment related to this _dl_sort_maps change is the removing of two char arrays 'used' and 'done' in _dl_close_worker to represent two per-map attributes. This has been changed to simply use two new bit-fields l_map_used:1, l_map_done:1 added to struct link_map. This also allows discarding the clunky 'used' array sorting that _dl_sort_maps had to sometimes do along the way. Tunable support for switching between different sorting algorithms at runtime is also added. A new tunable 'glibc.rtld.dynamic_sort' with current valid values 1 (old algorithm) and 2 (new DFS algorithm) has been added. At time of commit of this patch, the default setting is 1 (old algorithm). Signed-off-by: Chung-Lin Tang <cltang@codesourcery.com> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2021-10-21 13:41:22 +00:00
output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
elf: Testing infrastructure for ld.so DSO sorting (BZ #17645) This is the first of a 2-part patch set that fixes slow DSO sorting behavior in the dynamic loader, as reported in BZ #17645. In order to facilitate such a large modification to the dynamic loader, this first patch implements a testing framework for validating shared object sorting behavior, to enable comparison between old/new sorting algorithms, and any later enhancements. This testing infrastructure consists of a Python script scripts/dso-ordering-test.py' which takes in a description language, consisting of strings that describe a set of link dependency relations between DSOs, and generates testcase programs and Makefile fragments to automatically test the described situation, for example: a->b->c->d # four objects linked one after another a->[bc]->d;b->c # a depends on b and c, which both depend on d, # b depends on c (b,c linked to object a in fixed order) a->b->c;{+a;%a;-a} # a, b, c serially dependent, main program uses # dlopen/dlsym/dlclose on object a a->b->c;{}!->[abc] # a, b, c serially dependent; multiple tests generated # to test all permutations of a, b, c ordering linked # to main program (Above is just a short description of what the script can do, more documentation is in the script comments.) Two files containing several new tests, elf/dso-sort-tests-[12].def are added, including test scenarios for BZ #15311 and Redhat issue #1162810 [1]. Due to the nature of dynamic loader tests, where the sorting behavior and test output occurs before/after main(), generating testcases to use support/test-driver.c does not suffice to control meaningful timeout for ld.so. Therefore a new utility program 'support/test-run-command', based on test-driver.c/support_test_main.c has been added. This does the same testcase control, but for a program specified through a command-line rather than at the source code level. This utility is used to run the dynamic loader testcases generated by dso-ordering-test.py. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1162810 Signed-off-by: Chung-Lin Tang <cltang@codesourcery.com> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2021-10-21 13:41:21 +00:00
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
# Test that even in the presence of dependency loops involving dlopen'ed
# object, that object is initialized last (and not unloaded prematurely).
# Final destructor order is indeterminate due to the cycle.
tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1