1 | /* Bug 11941: Improper assert map->l_init_called in dlclose. |
2 | Copyright (C) 2016-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 is the primary DSO that is loaded by the appliation. This DSO |
20 | then loads a plugin with RTLD_NODELETE. This plugin depends on this |
21 | DSO. This dependency chain means that at application shutdown the |
22 | plugin will be destructed first. Thus by the time this DSO is |
23 | destructed we will be calling dlclose on an object that has already |
24 | been destructed. It is allowed to call dlclose in this way and |
25 | should not assert. */ |
26 | #include <stdio.h> |
27 | #include <stdlib.h> |
28 | #include <dlfcn.h> |
29 | |
30 | /* Plugin to load. */ |
31 | static void *plugin_lib = NULL; |
32 | /* Plugin function. */ |
33 | static void (*plugin_func) (void); |
34 | #define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so" |
35 | |
36 | /* This function is never called but the plugin references it. |
37 | We do this to avoid any future --as-needed from removing the |
38 | plugin's DT_NEEDED on this DSO (required for the test). */ |
39 | void |
40 | primary_reference (void) |
41 | { |
42 | printf (format: "INFO: Called primary_reference function.\n" ); |
43 | } |
44 | |
45 | void |
46 | primary (void) |
47 | { |
48 | char *error; |
49 | |
50 | plugin_lib = dlopen (LIB_PLUGIN, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); |
51 | if (plugin_lib == NULL) |
52 | { |
53 | printf (format: "ERROR: Unable to load plugin library.\n" ); |
54 | exit (EXIT_FAILURE); |
55 | } |
56 | dlerror (); |
57 | |
58 | plugin_func = (void (*) (void)) dlsym (handle: plugin_lib, name: "plugin_func" ); |
59 | error = dlerror (); |
60 | if (error != NULL) |
61 | { |
62 | printf (format: "ERROR: Unable to find symbol with error \"%s\"." , |
63 | error); |
64 | exit (EXIT_FAILURE); |
65 | } |
66 | |
67 | return; |
68 | } |
69 | |
70 | __attribute__ ((destructor)) |
71 | static void |
72 | primary_dtor (void) |
73 | { |
74 | int ret; |
75 | |
76 | printf (format: "INFO: Calling primary destructor.\n" ); |
77 | |
78 | /* The destructor runs in the test driver also, which |
79 | hasn't called primary, in that case do nothing. */ |
80 | if (plugin_lib == NULL) |
81 | return; |
82 | |
83 | ret = dlclose (handle: plugin_lib); |
84 | if (ret != 0) |
85 | { |
86 | printf (format: "ERROR: Calling dlclose failed with \"%s\"\n" , |
87 | dlerror ()); |
88 | exit (EXIT_FAILURE); |
89 | } |
90 | } |
91 | |