Blame elf/dl-exception.c

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