1 /* Return error detail for failing <dlfcn.h> functions.
2 Copyright (C) 1995-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
25 #include <libc-lock.h>
27 #include <libc-symbols.h>
31 #if !defined SHARED && IS_IN (libdl)
46 return _dlfcn_hook
->dlerror ();
49 struct dl_action_result
*result
= __libc_dlerror_result
;
51 /* No libdl function has been called. No error is possible. */
55 /* For an early malloc failure, clear the error flag and return the
56 error message. This marks the error as delivered. */
57 if (result
== dl_action_result_malloc_failed
)
59 __libc_dlerror_result
= NULL
;
60 return (char *) "out of memory";
63 /* Placeholder object. This can be observed in a recursive call,
64 e.g. from an ELF constructor. */
65 if (result
->errstring
== NULL
)
68 /* If we have already reported the error, we can free the result and
69 return NULL. See __libc_dlerror_result_free. */
72 __libc_dlerror_result
= NULL
;
73 dl_action_result_errstring_free (result
);
78 assert (result
->errstring
!= NULL
);
80 /* Create the combined error message. */
83 if (result
->errcode
== 0)
84 n
= __asprintf (&buf
, "%s%s%s",
86 result
->objname
[0] == '\0' ? "" : ": ",
87 _(result
->errstring
));
89 n
= __asprintf (&buf
, "%s%s%s: %s",
91 result
->objname
[0] == '\0' ? "" : ": ",
93 strerror (result
->errcode
));
95 /* Mark the error as delivered. */
96 result
->returned
= true;
100 /* Replace the error string with the newly allocated one. */
101 dl_action_result_errstring_free (result
);
102 result
->errstring
= buf
;
103 result
->errstring_source
= dl_action_result_errstring_local
;
107 /* We could not create the combined error message, so use the
108 existing string as a fallback. */
109 return result
->errstring
;
112 strong_alias (__dlerror
, dlerror
)
116 _dlerror_run (void (*operate
) (void *), void *args
)
118 struct dl_action_result
*result
= __libc_dlerror_result
;
121 if (result
== dl_action_result_malloc_failed
)
123 /* Clear the previous error. */
124 __libc_dlerror_result
= NULL
;
129 /* There is an existing object. Free its error string, but
131 dl_action_result_errstring_free (result
);
132 /* Mark the object as not containing an error. This ensures
133 that call to dlerror from, for example, an ELF
134 constructor will not notice this result object. */
135 result
->errstring
= NULL
;
140 const char *errstring
;
142 int errcode
= GLRO (dl_catch_error
) (&objname
, &errstring
, &malloced
,
145 /* ELF constructors or destructors may have indirectly altered the
146 value of __libc_dlerror_result, therefore reload it. */
147 result
= __libc_dlerror_result
;
149 if (errstring
== NULL
)
151 /* There is no error. We no longer need the result object if it
152 does not contain an error. However, a recursive call may
153 have added an error even if this call did not cause it. Keep
155 if (result
!= NULL
&& result
->errstring
== NULL
)
157 __libc_dlerror_result
= NULL
;
164 /* A new error occurred. Check if a result object has to be
166 if (result
== NULL
|| result
== dl_action_result_malloc_failed
)
168 /* Allocating storage for the error message after the fact
169 is not ideal. But this avoids an infinite recursion in
170 case malloc itself calls libdl functions (without
171 triggering errors). */
172 result
= malloc (sizeof (*result
));
175 /* Assume that the dlfcn failure was due to a malloc
178 dl_error_free ((char *) errstring
);
179 __libc_dlerror_result
= dl_action_result_malloc_failed
;
182 __libc_dlerror_result
= result
;
185 /* Deallocate the existing error message from a recursive
186 call, but reuse the result object. */
187 dl_action_result_errstring_free (result
);
189 result
->errcode
= errcode
;
190 result
->objname
= objname
;
191 result
->errstring
= (char *) errstring
;
192 result
->returned
= false;
193 /* In case of an error, the malloced flag indicates whether the
194 error string is constant or not. */
196 result
->errstring_source
= dl_action_result_errstring_rtld
;
198 result
->errstring_source
= dl_action_result_errstring_constant
;
206 struct dlfcn_hook
*_dlfcn_hook
__attribute__((nocommon
));
207 libdl_hidden_data_def (_dlfcn_hook
)
211 static struct dlfcn_hook _dlfcn_hooks
=
214 .dlclose
= __dlclose
,
217 .dlerror
= __dlerror
,
219 .dladdr1
= __dladdr1
,
225 __libc_register_dlfcn_hook (struct link_map
*map
)
227 struct dlfcn_hook
**hook
;
229 hook
= (struct dlfcn_hook
**) __libc_dlsym_private (map
, "_dlfcn_hook");
231 *hook
= &_dlfcn_hooks
;