]>
Commit | Line | Data |
---|---|---|
ccdb048d | 1 | /* Test recursive dlopen using malloc hooks. |
04277e02 | 2 | Copyright (C) 2015-2019 Free Software Foundation, Inc. |
ccdb048d | 3 | This file is part of the GNU C Library. |
ccdb048d CD |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
ccdb048d CD |
18 | |
19 | #include <stdio.h> | |
20 | #include <stdlib.h> | |
ccdb048d | 21 | #include <dlfcn.h> |
91e2b5cf FW |
22 | #include <stdbool.h> |
23 | #include <stdalign.h> | |
24 | #include <sys/mman.h> | |
25 | #include <unistd.h> | |
b5537473 | 26 | #include <string.h> |
ccdb048d CD |
27 | |
28 | #define DSO "moddummy1.so" | |
29 | #define FUNC "dummy1" | |
30 | ||
31 | #define DSO1 "moddummy2.so" | |
32 | #define FUNC1 "dummy2" | |
33 | ||
34 | /* Result of the called function. */ | |
35 | int func_result; | |
36 | ||
ccdb048d CD |
37 | /* Call function func_name in DSO dso_name via dlopen. */ |
38 | void | |
39 | call_func (const char *dso_name, const char *func_name) | |
40 | { | |
41 | int ret; | |
42 | void *dso; | |
43 | int (*func) (void); | |
44 | char *err; | |
45 | ||
46 | /* Open the DSO. */ | |
47 | dso = dlopen (dso_name, RTLD_NOW|RTLD_GLOBAL); | |
48 | if (dso == NULL) | |
49 | { | |
50 | err = dlerror (); | |
51 | fprintf (stderr, "%s\n", err); | |
52 | exit (1); | |
53 | } | |
54 | /* Clear any errors. */ | |
55 | dlerror (); | |
56 | ||
57 | /* Lookup func. */ | |
04ae79a3 | 58 | func = (int (*) (void)) dlsym (dso, func_name); |
ccdb048d CD |
59 | if (func == NULL) |
60 | { | |
61 | err = dlerror (); | |
62 | if (err != NULL) | |
63 | { | |
64 | fprintf (stderr, "%s\n", err); | |
65 | exit (1); | |
66 | } | |
67 | } | |
68 | /* Call func. */ | |
69 | func_result = (*func) (); | |
70 | ||
71 | /* Close the library and look for errors too. */ | |
72 | ret = dlclose (dso); | |
73 | if (ret != 0) | |
74 | { | |
75 | err = dlerror (); | |
76 | fprintf (stderr, "%s\n", err); | |
77 | exit (1); | |
78 | } | |
79 | ||
80 | } | |
81 | ||
91e2b5cf FW |
82 | /* If true, call another function from malloc. */ |
83 | static bool call_function; | |
84 | ||
85 | /* Set to true to indicate that the interposed malloc was called. */ | |
86 | static bool interposed_malloc_called; | |
87 | ||
88 | /* Interposed malloc which optionally calls another function. */ | |
ccdb048d | 89 | void * |
91e2b5cf | 90 | malloc (size_t size) |
ccdb048d | 91 | { |
91e2b5cf FW |
92 | interposed_malloc_called = true; |
93 | static void *(*original_malloc) (size_t); | |
94 | ||
95 | if (original_malloc == NULL) | |
96 | { | |
97 | static bool in_initialization; | |
98 | if (in_initialization) | |
99 | { | |
100 | const char *message | |
101 | = "error: malloc called recursively during initialization\n"; | |
102 | (void) write (STDOUT_FILENO, message, strlen (message)); | |
103 | _exit (2); | |
104 | } | |
105 | in_initialization = true; | |
106 | ||
107 | original_malloc | |
108 | = (__typeof (original_malloc)) dlsym (RTLD_NEXT, "malloc"); | |
109 | if (original_malloc == NULL) | |
110 | { | |
111 | const char *message | |
112 | = "error: dlsym for malloc failed\n"; | |
113 | (void) write (STDOUT_FILENO, message, strlen (message)); | |
114 | _exit (2); | |
115 | } | |
116 | } | |
117 | ||
118 | if (call_function) | |
119 | { | |
120 | call_function = false; | |
121 | call_func (DSO1, FUNC1); | |
122 | call_function = true; | |
123 | } | |
124 | return original_malloc (size); | |
ccdb048d CD |
125 | } |
126 | ||
127 | static int | |
128 | do_test (void) | |
129 | { | |
91e2b5cf FW |
130 | /* Ensure initialization. */ |
131 | { | |
132 | void *volatile ptr = malloc (1); | |
133 | free (ptr); | |
134 | } | |
135 | ||
136 | if (!interposed_malloc_called) | |
137 | { | |
138 | printf ("error: interposed malloc not called during initialization\n"); | |
139 | return 1; | |
140 | } | |
141 | ||
142 | call_function = true; | |
ccdb048d CD |
143 | |
144 | /* Bug 17702 fixes two things: | |
145 | * A recursive dlopen unmapping the ld.so.cache. | |
146 | * An assertion that _r_debug is RT_CONSISTENT at entry to dlopen. | |
147 | We can only test the latter. Testing the former requires modifying | |
148 | ld.so.conf to cache the dummy libraries, then running ldconfig, | |
149 | then run the test. If you do all of that (and glibc's test | |
150 | infrastructure doesn't support that yet) then the test will | |
151 | SEGFAULT without the fix. If you don't do that, then the test | |
152 | will abort because of the assert described in detail below. */ | |
153 | call_func (DSO, FUNC); | |
154 | ||
91e2b5cf | 155 | call_function = false; |
ccdb048d CD |
156 | |
157 | /* The function dummy2() is called by the malloc hook. Check to | |
158 | see that it was called. This ensures the second recursive | |
159 | dlopen happened and we called the function in that library. | |
160 | Before the fix you either get a SIGSEGV when accessing mmap'd | |
161 | ld.so.cache data or an assertion failure about _r_debug not | |
162 | beint RT_CONSISTENT. We don't test for the SIGSEGV since it | |
163 | would require finding moddummy1 or moddummy2 in the cache and | |
164 | we don't have any infrastructure to test that, but the _r_debug | |
165 | assertion triggers. */ | |
166 | printf ("Returned result is %d\n", func_result); | |
167 | if (func_result <= 0) | |
168 | { | |
169 | printf ("FAIL: Function call_func() not called.\n"); | |
170 | exit (1); | |
171 | } | |
172 | ||
173 | printf ("PASS: Function call_func() called more than once.\n"); | |
174 | return 0; | |
175 | } | |
176 | ||
177 | #define TEST_FUNCTION do_test () | |
178 | #include "../test-skeleton.c" |