1 /* Return error detail for failing <dlfcn.h> functions.
2 Copyright (C) 1995-2023 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>
35 if (GLRO (dl_dlfcn_hook
) != NULL
)
36 return GLRO (dl_dlfcn_hook
)->dlerror ();
39 struct dl_action_result
*result
= __libc_dlerror_result
;
41 /* No libdl function has been called. No error is possible. */
45 /* For an early malloc failure, clear the error flag and return the
46 error message. This marks the error as delivered. */
47 if (result
== dl_action_result_malloc_failed
)
49 __libc_dlerror_result
= NULL
;
50 return (char *) "out of memory";
53 /* Placeholder object. This can be observed in a recursive call,
54 e.g. from an ELF constructor. */
55 if (result
->errstring
== NULL
)
58 /* If we have already reported the error, we can free the result and
59 return NULL. See __libc_dlerror_result_free. */
62 __libc_dlerror_result
= NULL
;
63 dl_action_result_errstring_free (result
);
68 assert (result
->errstring
!= NULL
);
70 /* Create the combined error message. */
73 if (result
->errcode
== 0)
74 n
= __asprintf (&buf
, "%s%s%s",
76 result
->objname
[0] == '\0' ? "" : ": ",
77 _(result
->errstring
));
80 __set_errno (result
->errcode
);
81 n
= __asprintf (&buf
, "%s%s%s: %m",
83 result
->objname
[0] == '\0' ? "" : ": ",
84 _(result
->errstring
));
85 /* Set errno again in case asprintf clobbered it. */
86 __set_errno (result
->errcode
);
89 /* Mark the error as delivered. */
90 result
->returned
= true;
94 /* Replace the error string with the newly allocated one. */
95 dl_action_result_errstring_free (result
);
96 result
->errstring
= buf
;
97 result
->errstring_source
= dl_action_result_errstring_local
;
101 /* We could not create the combined error message, so use the
102 existing string as a fallback. */
103 return result
->errstring
;
105 versioned_symbol (libc
, __dlerror
, dlerror
, GLIBC_2_34
);
107 #if OTHER_SHLIB_COMPAT (libdl, GLIBC_2_0, GLIBC_2_34)
108 compat_symbol (libdl
, __dlerror
, dlerror
, GLIBC_2_0
);
112 _dlerror_run (void (*operate
) (void *), void *args
)
114 struct dl_action_result
*result
= __libc_dlerror_result
;
117 if (result
== dl_action_result_malloc_failed
)
119 /* Clear the previous error. */
120 __libc_dlerror_result
= NULL
;
125 /* There is an existing object. Free its error string, but
127 dl_action_result_errstring_free (result
);
128 /* Mark the object as not containing an error. This ensures
129 that call to dlerror from, for example, an ELF
130 constructor will not notice this result object. */
131 result
->errstring
= NULL
;
136 const char *errstring
;
138 int errcode
= GLRO (dl_catch_error
) (&objname
, &errstring
, &malloced
,
141 /* ELF constructors or destructors may have indirectly altered the
142 value of __libc_dlerror_result, therefore reload it. */
143 result
= __libc_dlerror_result
;
145 if (errstring
== NULL
)
147 /* There is no error. We no longer need the result object if it
148 does not contain an error. However, a recursive call may
149 have added an error even if this call did not cause it. Keep
151 if (result
!= NULL
&& result
->errstring
== NULL
)
153 __libc_dlerror_result
= NULL
;
160 /* A new error occurred. Check if a result object has to be
162 if (result
== NULL
|| result
== dl_action_result_malloc_failed
)
164 /* Allocating storage for the error message after the fact
165 is not ideal. But this avoids an infinite recursion in
166 case malloc itself calls libdl functions (without
167 triggering errors). */
168 result
= malloc (sizeof (*result
));
171 /* Assume that the dlfcn failure was due to a malloc
174 dl_error_free ((char *) errstring
);
175 __libc_dlerror_result
= dl_action_result_malloc_failed
;
178 __libc_dlerror_result
= result
;
181 /* Deallocate the existing error message from a recursive
182 call, but reuse the result object. */
183 dl_action_result_errstring_free (result
);
185 result
->errcode
= errcode
;
186 result
->objname
= objname
;
187 result
->errstring
= (char *) errstring
;
188 result
->returned
= false;
189 /* In case of an error, the malloced flag indicates whether the
190 error string is constant or not. */
192 result
->errstring_source
= dl_action_result_errstring_rtld
;
194 result
->errstring_source
= dl_action_result_errstring_constant
;