|
Packit |
6c4009 |
/* ld.so error exception allocation and deallocation.
|
|
Packit |
6c4009 |
Copyright (C) 1995-2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library; if not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include <ldsodefs.h>
|
|
Packit |
6c4009 |
#include <limits.h>
|
|
Packit |
6c4009 |
#include <stdarg.h>
|
|
Packit |
6c4009 |
#include <stdbool.h>
|
|
Packit |
6c4009 |
#include <stdint.h>
|
|
Packit |
6c4009 |
#include <string.h>
|
|
Packit |
6c4009 |
#include <unistd.h>
|
|
Packit Service |
ff57fc |
#include <_itoa.h>
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* This message we return as a last resort. We define the string in a
|
|
Packit |
6c4009 |
variable since we have to avoid freeing it and so have to enable
|
|
Packit |
6c4009 |
a pointer comparison. See below and in dlfcn/dlerror.c. */
|
|
Packit |
6c4009 |
static const char _dl_out_of_memory[] = "out of memory";
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Dummy allocation object used if allocating the message buffer
|
|
Packit |
6c4009 |
fails. */
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
oom_exception (struct dl_exception *exception)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
exception->objname = "";
|
|
Packit |
6c4009 |
exception->errstring = _dl_out_of_memory;
|
|
Packit |
6c4009 |
exception->message_buffer = NULL;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
__attribute__ ((noreturn))
|
|
Packit |
6c4009 |
length_mismatch (void)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
_dl_fatal_printf ("Fatal error: "
|
|
Packit |
6c4009 |
"length accounting in _dl_exception_create_format\n");
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Adjust the message buffer to indicate whether it is possible to
|
|
Packit |
6c4009 |
free it. EXCEPTION->errstring must be a potentially deallocatable
|
|
Packit |
6c4009 |
pointer. */
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
adjust_message_buffer (struct dl_exception *exception)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* If the main executable is relocated it means the libc's malloc
|
|
Packit |
6c4009 |
is used. */
|
|
Packit |
6c4009 |
bool malloced = true;
|
|
Packit |
6c4009 |
#ifdef SHARED
|
|
Packit |
6c4009 |
malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
|
|
Packit |
6c4009 |
&& (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
if (malloced)
|
|
Packit |
6c4009 |
exception->message_buffer = (char *) exception->errstring;
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
exception->message_buffer = NULL;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
void
|
|
Packit |
6c4009 |
_dl_exception_create (struct dl_exception *exception, const char *objname,
|
|
Packit |
6c4009 |
const char *errstring)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (objname == NULL)
|
|
Packit |
6c4009 |
objname = "";
|
|
Packit |
6c4009 |
size_t len_objname = strlen (objname) + 1;
|
|
Packit |
6c4009 |
size_t len_errstring = strlen (errstring) + 1;
|
|
Packit |
6c4009 |
char *errstring_copy = malloc (len_objname + len_errstring);
|
|
Packit |
6c4009 |
if (errstring_copy != NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* Make a copy of the object file name and the error string. */
|
|
Packit |
6c4009 |
exception->objname = memcpy (__mempcpy (errstring_copy,
|
|
Packit |
6c4009 |
errstring, len_errstring),
|
|
Packit |
6c4009 |
objname, len_objname);
|
|
Packit |
6c4009 |
exception->errstring = errstring_copy;
|
|
Packit |
6c4009 |
adjust_message_buffer (exception);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
oom_exception (exception);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
rtld_hidden_def (_dl_exception_create)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
void
|
|
Packit |
6c4009 |
_dl_exception_create_format (struct dl_exception *exception, const char *objname,
|
|
Packit |
6c4009 |
const char *fmt, ...)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (objname == NULL)
|
|
Packit |
6c4009 |
objname = "";
|
|
Packit |
6c4009 |
size_t len_objname = strlen (objname) + 1;
|
|
Packit |
6c4009 |
/* Compute the length of the result. Include room for two NUL
|
|
Packit |
6c4009 |
bytes. */
|
|
Packit |
6c4009 |
size_t length = len_objname + 1;
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
va_list ap;
|
|
Packit |
6c4009 |
va_start (ap, fmt);
|
|
Packit |
6c4009 |
for (const char *p = fmt; *p != '\0'; ++p)
|
|
Packit |
6c4009 |
if (*p == '%')
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
++p;
|
|
Packit |
6c4009 |
switch (*p)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
case 's':
|
|
Packit |
6c4009 |
length += strlen (va_arg (ap, const char *));
|
|
Packit |
6c4009 |
break;
|
|
Packit Service |
270f09 |
/* Recognize the l modifier. It is only important on some
|
|
Packit Service |
270f09 |
platforms where long and int have a different size. We
|
|
Packit Service |
270f09 |
can use the same code for size_t. */
|
|
Packit Service |
270f09 |
case 'l':
|
|
Packit Service |
270f09 |
case 'z':
|
|
Packit Service |
270f09 |
if (p[1] == 'x')
|
|
Packit Service |
270f09 |
{
|
|
Packit Service |
270f09 |
length += LONG_WIDTH / 4;
|
|
Packit Service |
270f09 |
++p;
|
|
Packit Service |
270f09 |
break;
|
|
Packit Service |
270f09 |
}
|
|
Packit Service |
826702 |
/* Fall through. */
|
|
Packit Service |
270f09 |
case 'x':
|
|
Packit Service |
270f09 |
length += INT_WIDTH / 4;
|
|
Packit Service |
270f09 |
break;
|
|
Packit |
6c4009 |
default:
|
|
Packit |
6c4009 |
/* Assumed to be '%'. */
|
|
Packit |
6c4009 |
++length;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
++length;
|
|
Packit |
6c4009 |
va_end (ap);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (length > PTRDIFF_MAX)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
oom_exception (exception);
|
|
Packit |
6c4009 |
return;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
char *errstring = malloc (length);
|
|
Packit |
6c4009 |
if (errstring == NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
oom_exception (exception);
|
|
Packit |
6c4009 |
return;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
exception->errstring = errstring;
|
|
Packit |
6c4009 |
adjust_message_buffer (exception);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Copy the error message to errstring. */
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* Next byte to be written in errstring. */
|
|
Packit |
6c4009 |
char *wptr = errstring;
|
|
Packit |
6c4009 |
/* End of the allocated string. */
|
|
Packit |
6c4009 |
char *const end = errstring + length;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
va_list ap;
|
|
Packit |
6c4009 |
va_start (ap, fmt);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
for (const char *p = fmt; *p != '\0'; ++p)
|
|
Packit |
6c4009 |
if (*p == '%')
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
++p;
|
|
Packit |
6c4009 |
switch (*p)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
case 's':
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
const char *ptr = va_arg (ap, const char *);
|
|
Packit |
6c4009 |
size_t len_ptr = strlen (ptr);
|
|
Packit |
6c4009 |
if (len_ptr > end - wptr)
|
|
Packit |
6c4009 |
length_mismatch ();
|
|
Packit |
6c4009 |
wptr = __mempcpy (wptr, ptr, len_ptr);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case '%':
|
|
Packit |
6c4009 |
if (wptr == end)
|
|
Packit |
6c4009 |
length_mismatch ();
|
|
Packit |
6c4009 |
*wptr = '%';
|
|
Packit |
6c4009 |
++wptr;
|
|
Packit |
6c4009 |
break;
|
|
Packit Service |
270f09 |
case 'x':
|
|
Packit Service |
270f09 |
{
|
|
Packit Service |
270f09 |
unsigned long int num = va_arg (ap, unsigned int);
|
|
Packit Service |
270f09 |
char *start = wptr;
|
|
Packit Service |
270f09 |
wptr += INT_WIDTH / 4;
|
|
Packit Service |
270f09 |
char *cp = _itoa (num, wptr, 16, 0);
|
|
Packit Service |
270f09 |
/* Pad to the full width with 0. */
|
|
Packit Service |
270f09 |
while (cp != start)
|
|
Packit Service |
270f09 |
*--cp = '0';
|
|
Packit Service |
270f09 |
}
|
|
Packit Service |
270f09 |
break;
|
|
Packit Service |
270f09 |
case 'l':
|
|
Packit Service |
270f09 |
case 'z':
|
|
Packit Service |
270f09 |
if (p[1] == 'x')
|
|
Packit Service |
270f09 |
{
|
|
Packit Service |
270f09 |
unsigned long int num = va_arg (ap, unsigned long int);
|
|
Packit Service |
270f09 |
char *start = wptr;
|
|
Packit Service |
270f09 |
wptr += LONG_WIDTH / 4;
|
|
Packit Service |
270f09 |
char *cp = _itoa (num, wptr, 16, 0);
|
|
Packit Service |
270f09 |
/* Pad to the full width with 0. */
|
|
Packit Service |
270f09 |
while (cp != start)
|
|
Packit Service |
270f09 |
*--cp = '0';
|
|
Packit Service |
270f09 |
++p;
|
|
Packit Service |
270f09 |
break;
|
|
Packit Service |
270f09 |
}
|
|
Packit Service |
270f09 |
/* FALLTHROUGH */
|
|
Packit |
6c4009 |
default:
|
|
Packit |
6c4009 |
_dl_fatal_printf ("Fatal error:"
|
|
Packit |
6c4009 |
" invalid format in exception string\n");
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (wptr == end)
|
|
Packit |
6c4009 |
length_mismatch ();
|
|
Packit |
6c4009 |
*wptr = *p;
|
|
Packit |
6c4009 |
++wptr;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (wptr == end)
|
|
Packit |
6c4009 |
length_mismatch ();
|
|
Packit |
6c4009 |
*wptr = '\0';
|
|
Packit |
6c4009 |
++wptr;
|
|
Packit |
6c4009 |
if (len_objname != end - wptr)
|
|
Packit |
6c4009 |
length_mismatch ();
|
|
Packit |
6c4009 |
exception->objname = memcpy (wptr, objname, len_objname);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
rtld_hidden_def (_dl_exception_create_format)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
void
|
|
Packit |
6c4009 |
_dl_exception_free (struct dl_exception *exception)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
free (exception->message_buffer);
|
|
Packit |
6c4009 |
exception->objname = NULL;
|
|
Packit |
6c4009 |
exception->errstring = NULL;
|
|
Packit |
6c4009 |
exception->message_buffer = NULL;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
rtld_hidden_def (_dl_exception_free)
|