]> git.ipfire.org Git - thirdparty/glibc.git/blob - elf/dl-exception.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / elf / dl-exception.c
1 /* ld.so error exception allocation and deallocation.
2 Copyright (C) 1995-2019 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 <http://www.gnu.org/licenses/>. */
18
19 #include <ldsodefs.h>
20 #include <limits.h>
21 #include <stdarg.h>
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <_itoa.h>
27
28 /* This message we return as a last resort. We define the string in a
29 variable since we have to avoid freeing it and so have to enable
30 a pointer comparison. See below and in dlfcn/dlerror.c. */
31 static const char _dl_out_of_memory[] = "out of memory";
32
33 /* Dummy allocation object used if allocating the message buffer
34 fails. */
35 static void
36 oom_exception (struct dl_exception *exception)
37 {
38 exception->objname = "";
39 exception->errstring = _dl_out_of_memory;
40 exception->message_buffer = NULL;
41 }
42
43 static void
44 __attribute__ ((noreturn))
45 length_mismatch (void)
46 {
47 _dl_fatal_printf ("Fatal error: "
48 "length accounting in _dl_exception_create_format\n");
49 }
50
51 /* Adjust the message buffer to indicate whether it is possible to
52 free it. EXCEPTION->errstring must be a potentially deallocatable
53 pointer. */
54 static void
55 adjust_message_buffer (struct dl_exception *exception)
56 {
57 /* If the main executable is relocated it means the libc's malloc
58 is used. */
59 bool malloced = true;
60 #ifdef SHARED
61 malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
62 && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
63 #endif
64 if (malloced)
65 exception->message_buffer = (char *) exception->errstring;
66 else
67 exception->message_buffer = NULL;
68 }
69
70 void
71 _dl_exception_create (struct dl_exception *exception, const char *objname,
72 const char *errstring)
73 {
74 if (objname == NULL)
75 objname = "";
76 size_t len_objname = strlen (objname) + 1;
77 size_t len_errstring = strlen (errstring) + 1;
78 char *errstring_copy = malloc (len_objname + len_errstring);
79 if (errstring_copy != NULL)
80 {
81 /* Make a copy of the object file name and the error string. */
82 exception->objname = memcpy (__mempcpy (errstring_copy,
83 errstring, len_errstring),
84 objname, len_objname);
85 exception->errstring = errstring_copy;
86 adjust_message_buffer (exception);
87 }
88 else
89 oom_exception (exception);
90 }
91 rtld_hidden_def (_dl_exception_create)
92
93 void
94 _dl_exception_create_format (struct dl_exception *exception, const char *objname,
95 const char *fmt, ...)
96 {
97 if (objname == NULL)
98 objname = "";
99 size_t len_objname = strlen (objname) + 1;
100 /* Compute the length of the result. Include room for two NUL
101 bytes. */
102 size_t length = len_objname + 1;
103 {
104 va_list ap;
105 va_start (ap, fmt);
106 for (const char *p = fmt; *p != '\0'; ++p)
107 if (*p == '%')
108 {
109 ++p;
110 switch (*p)
111 {
112 case 's':
113 length += strlen (va_arg (ap, const char *));
114 break;
115 /* Recognize the l modifier. It is only important on some
116 platforms where long and int have a different size. We
117 can use the same code for size_t. */
118 case 'l':
119 case 'z':
120 if (p[1] == 'x')
121 {
122 length += LONG_WIDTH / 4;
123 ++p;
124 break;
125 }
126 case 'x':
127 length += INT_WIDTH / 4;
128 break;
129 default:
130 /* Assumed to be '%'. */
131 ++length;
132 break;
133 }
134 }
135 else
136 ++length;
137 va_end (ap);
138 }
139
140 if (length > PTRDIFF_MAX)
141 {
142 oom_exception (exception);
143 return;
144 }
145 char *errstring = malloc (length);
146 if (errstring == NULL)
147 {
148 oom_exception (exception);
149 return;
150 }
151 exception->errstring = errstring;
152 adjust_message_buffer (exception);
153
154 /* Copy the error message to errstring. */
155 {
156 /* Next byte to be written in errstring. */
157 char *wptr = errstring;
158 /* End of the allocated string. */
159 char *const end = errstring + length;
160
161 va_list ap;
162 va_start (ap, fmt);
163
164 for (const char *p = fmt; *p != '\0'; ++p)
165 if (*p == '%')
166 {
167 ++p;
168 switch (*p)
169 {
170 case 's':
171 {
172 const char *ptr = va_arg (ap, const char *);
173 size_t len_ptr = strlen (ptr);
174 if (len_ptr > end - wptr)
175 length_mismatch ();
176 wptr = __mempcpy (wptr, ptr, len_ptr);
177 }
178 break;
179 case '%':
180 if (wptr == end)
181 length_mismatch ();
182 *wptr = '%';
183 ++wptr;
184 break;
185 case 'x':
186 {
187 unsigned long int num = va_arg (ap, unsigned int);
188 char *start = wptr;
189 wptr += INT_WIDTH / 4;
190 char *cp = _itoa (num, wptr, 16, 0);
191 /* Pad to the full width with 0. */
192 while (cp != start)
193 *--cp = '0';
194 }
195 break;
196 case 'l':
197 case 'z':
198 if (p[1] == 'x')
199 {
200 unsigned long int num = va_arg (ap, unsigned long int);
201 char *start = wptr;
202 wptr += LONG_WIDTH / 4;
203 char *cp = _itoa (num, wptr, 16, 0);
204 /* Pad to the full width with 0. */
205 while (cp != start)
206 *--cp = '0';
207 ++p;
208 break;
209 }
210 /* FALLTHROUGH */
211 default:
212 _dl_fatal_printf ("Fatal error:"
213 " invalid format in exception string\n");
214 }
215 }
216 else
217 {
218 if (wptr == end)
219 length_mismatch ();
220 *wptr = *p;
221 ++wptr;
222 }
223
224 if (wptr == end)
225 length_mismatch ();
226 *wptr = '\0';
227 ++wptr;
228 if (len_objname != end - wptr)
229 length_mismatch ();
230 exception->objname = memcpy (wptr, objname, len_objname);
231 }
232 }
233 rtld_hidden_def (_dl_exception_create_format)
234
235 void
236 _dl_exception_free (struct dl_exception *exception)
237 {
238 free (exception->message_buffer);
239 exception->objname = NULL;
240 exception->errstring = NULL;
241 exception->message_buffer = NULL;
242 }
243 rtld_hidden_def (_dl_exception_free)