1 | /* Test interactions of dlopen, NODELETE, and relocations. |
2 | Copyright (C) 2019-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | /* This test exercises NODELETE propagation due to data relocations |
20 | and unique symbols, and the interaction with already-loaded |
21 | objects. Some test objects are written in C++, to produce unique |
22 | symbol definitions. |
23 | |
24 | First test: Global scope variant, data relocation as the NODELETE |
25 | trigger. mod1 is loaded first with a separate dlopen call. |
26 | |
27 | mod2 ---(may_finalize_mod1 relocation dependency)---> mod1 |
28 | (NODELETE) (marked as NODELETE) |
29 | |
30 | Second test: Local scope variant, data relocation. mod3 is loaded |
31 | first, then mod5. |
32 | |
33 | mod5 ---(DT_NEEDED)---> mod4 ---(DT_NEEDED)---> mod3 |
34 | (NODELETE) (not NODELETE) ^ |
35 | \ / (marked as |
36 | `--(may_finalize_mod3 relocation dependency)--/ NODELETE) |
37 | |
38 | Third test: Shared local scope with unique symbol. mod6 is loaded |
39 | first, then mod7. No explicit dependencies between the two |
40 | objects, so first object has to be opened with RTLD_GLOBAL. |
41 | |
42 | mod7 ---(unique symbol)---> mod6 |
43 | (marked as NODELETE) |
44 | |
45 | Forth test: Non-shared scopes with unique symbol. mod8 and mod10 |
46 | are loaded from the main program. mod8 loads mod9 from an ELF |
47 | constructor, mod10 loads mod11. There are no DT_NEEDED |
48 | dependencies. mod9 is promoted to the global scope form the main |
49 | program. The unique symbol dependency is: |
50 | |
51 | mod9 ---(unique symbol)---> mod11 |
52 | (marked as NODELETE) |
53 | |
54 | Fifth test: Shared local scope with unique symbol, like test 3, but |
55 | this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL |
56 | needed): |
57 | |
58 | DT_NEEDED |
59 | mod13 ---(unique symbol)---> mod12 |
60 | (marked as NODELETE) |
61 | |
62 | Sixth test: NODELETE status is retained after relocation failure |
63 | with unique symbol dependency. The object graph ensures that the |
64 | unique symbol binding is processed before the dlopen failure. |
65 | |
66 | DT_NEEDED |
67 | mod17 --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14 |
68 | \ ^ (RTLD_NODELETE) |
69 | \ (DT_NEEDED) |
70 | \ | |
71 | `---(DT_NEEDED)--> mod16 |
72 | (fails to relocate) |
73 | |
74 | mod14 is loaded first, and the loading mod17 is attempted. |
75 | mod14 must remain NODELETE after opening mod17 failed. */ |
76 | |
77 | #include <stdio.h> |
78 | #include <string.h> |
79 | #include <stdbool.h> |
80 | #include <support/check.h> |
81 | #include <support/xdlfcn.h> |
82 | |
83 | static int |
84 | do_test (void) |
85 | { |
86 | /* First case: global scope, regular data symbol. Open the object |
87 | which is not NODELETE initially. */ |
88 | void *mod1 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod1.so" , |
89 | RTLD_NOW | RTLD_GLOBAL); |
90 | /* This is used to indicate that the ELF destructor may be |
91 | called. */ |
92 | bool *may_finalize_mod1 = xdlsym (handle: mod1, symbol: "may_finalize_mod1" ); |
93 | /* Open the NODELETE object. */ |
94 | void *mod2 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod2.so" , RTLD_NOW); |
95 | /* This has no effect because the DSO is directly marked as |
96 | NODELETE. */ |
97 | xdlclose (handle: mod2); |
98 | /* This has no effect because the DSO has been indirectly marked as |
99 | NODELETE due to a relocation dependency. */ |
100 | xdlclose (handle: mod1); |
101 | |
102 | /* Second case: local scope, regular data symbol. Open the object |
103 | which is not NODELETE initially. */ |
104 | void *mod3 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod3.so" , RTLD_NOW); |
105 | bool *may_finalize_mod3 = xdlsym (handle: mod3, symbol: "may_finalize_mod3" ); |
106 | /* Open the NODELETE object. */ |
107 | void *mod5 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod5.so" , RTLD_NOW); |
108 | /* Again those have no effect because of NODELETE. */ |
109 | xdlclose (handle: mod5); |
110 | xdlclose (handle: mod3); |
111 | |
112 | /* Third case: Unique symbol. */ |
113 | void *mod6 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod6.so" , |
114 | RTLD_NOW | RTLD_GLOBAL); |
115 | bool *may_finalize_mod6 = xdlsym (handle: mod6, symbol: "may_finalize_mod6" ); |
116 | void *mod7 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod7.so" , RTLD_NOW); |
117 | bool *may_finalize_mod7 = xdlsym (handle: mod7, symbol: "may_finalize_mod7" ); |
118 | /* This should not have any effect because of the unique symbol and |
119 | the resulting NODELETE status. */ |
120 | xdlclose (handle: mod6); |
121 | /* mod7 is not NODELETE and can be closed. */ |
122 | *may_finalize_mod7 = true; |
123 | xdlclose (handle: mod7); |
124 | |
125 | /* Fourth case: Unique symbol, indirect loading. */ |
126 | void *mod8 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod8.so" , RTLD_NOW); |
127 | /* Also promote to global scope. */ |
128 | void *mod9 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod9.so" , |
129 | RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL); |
130 | bool *may_finalize_mod9 = xdlsym (handle: mod9, symbol: "may_finalize_mod9" ); |
131 | xdlclose (handle: mod9); /* Drop mod9 reference. */ |
132 | void *mod10 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod10.so" , RTLD_NOW); |
133 | void *mod11 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod11.so" , |
134 | RTLD_NOW | RTLD_NOLOAD); |
135 | bool *may_finalize_mod11 = xdlsym (handle: mod11, symbol: "may_finalize_mod11" ); |
136 | xdlclose (handle: mod11); /* Drop mod11 reference. */ |
137 | /* mod11 is not NODELETE and can be closed. */ |
138 | *may_finalize_mod11 = true; |
139 | /* Trigger closing of mod11, too. */ |
140 | xdlclose (handle: mod10); |
141 | /* Does not trigger closing of mod9. */ |
142 | xdlclose (handle: mod8); |
143 | |
144 | /* Fifth case: Unique symbol, with DT_NEEDED dependency. */ |
145 | void *mod12 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod12.so" , RTLD_NOW); |
146 | bool *may_finalize_mod12 = xdlsym (handle: mod12, symbol: "may_finalize_mod12" ); |
147 | void *mod13 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod13.so" , RTLD_NOW); |
148 | bool *may_finalize_mod13 = xdlsym (handle: mod13, symbol: "may_finalize_mod13" ); |
149 | /* This should not have any effect because of the unique symbol. */ |
150 | xdlclose (handle: mod12); |
151 | /* mod13 is not NODELETE and can be closed. */ |
152 | *may_finalize_mod13 = true; |
153 | xdlclose (handle: mod13); |
154 | |
155 | /* Sixth case: Unique symbol binding must not cause loss of NODELETE |
156 | status. */ |
157 | void *mod14 = xdlopen (filename: "tst-dlopen-nodelete-reloc-mod14.so" , |
158 | RTLD_NOW | RTLD_NODELETE); |
159 | bool *may_finalize_mod14 = xdlsym (handle: mod14, symbol: "may_finalize_mod14" ); |
160 | TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so" , RTLD_NOW) |
161 | == NULL); |
162 | const char *message = dlerror (); |
163 | printf (format: "info: test 6 message: %s\n" , message); |
164 | /* This must not close the object, it must still be NODELETE. */ |
165 | xdlclose (handle: mod14); |
166 | xdlopen (filename: "tst-dlopen-nodelete-reloc-mod14.so" , RTLD_NOW | RTLD_NOLOAD); |
167 | |
168 | /* Prepare for process exit. Destructors for NODELETE objects will |
169 | be invoked. */ |
170 | *may_finalize_mod1 = true; |
171 | *may_finalize_mod3 = true; |
172 | *may_finalize_mod6 = true; |
173 | *may_finalize_mod9 = true; |
174 | *may_finalize_mod12 = true; |
175 | *may_finalize_mod14 = true; |
176 | return 0; |
177 | } |
178 | |
179 | #include <support/test-driver.c> |
180 | |