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