1  /* Catastrophic failure reports.  Generic POSIX.1 version.
       2     Copyright (C) 1993-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 <atomic.h>
      20  #include <errno.h>
      21  #include <fcntl.h>
      22  #include <ldsodefs.h>
      23  #include <paths.h>
      24  #include <stdarg.h>
      25  #include <stdbool.h>
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <string.h>
      29  #include <sysdep.h>
      30  #include <unistd.h>
      31  #include <sys/mman.h>
      32  #include <sys/uio.h>
      33  #include <not-cancel.h>
      34  
      35  #ifdef FATAL_PREPARE_INCLUDE
      36  #include FATAL_PREPARE_INCLUDE
      37  #endif
      38  
      39  #ifndef WRITEV_FOR_FATAL
      40  # define WRITEV_FOR_FATAL	writev_for_fatal
      41  static bool
      42  writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total)
      43  {
      44    return TEMP_FAILURE_RETRY (__writev (fd, iov, niov)) == total;
      45  }
      46  #endif
      47  
      48  struct str_list
      49  {
      50    const char *str;
      51    size_t len;
      52    struct str_list *next;
      53  };
      54  
      55  /* Abort with an error message.  */
      56  void
      57  __libc_message (const char *fmt, ...)
      58  {
      59    va_list ap;
      60    int fd = -1;
      61  
      62    va_start (ap, fmt);
      63  
      64  #ifdef FATAL_PREPARE
      65    FATAL_PREPARE;
      66  #endif
      67  
      68    if (fd == -1)
      69      fd = STDERR_FILENO;
      70  
      71    struct str_list *list = NULL;
      72    int nlist = 0;
      73  
      74    const char *cp = fmt;
      75    while (*cp != '\0')
      76      {
      77        /* Find the next "%s" or the end of the string.  */
      78        const char *next = cp;
      79        while (next[0] != '%' || next[1] != 's')
      80  	{
      81  	  next = __strchrnul (next + 1, '%');
      82  
      83  	  if (next[0] == '\0')
      84  	    break;
      85  	}
      86  
      87        /* Determine what to print.  */
      88        const char *str;
      89        size_t len;
      90        if (cp[0] == '%' && cp[1] == 's')
      91  	{
      92  	  str = va_arg (ap, const char *);
      93  	  len = strlen (str);
      94  	  cp += 2;
      95  	}
      96        else
      97  	{
      98  	  str = cp;
      99  	  len = next - cp;
     100  	  cp = next;
     101  	}
     102  
     103        struct str_list *newp = alloca (sizeof (struct str_list));
     104        newp->str = str;
     105        newp->len = len;
     106        newp->next = list;
     107        list = newp;
     108        ++nlist;
     109      }
     110  
     111    if (nlist > 0)
     112      {
     113        struct iovec *iov = alloca (nlist * sizeof (struct iovec));
     114        ssize_t total = 0;
     115  
     116        for (int cnt = nlist - 1; cnt >= 0; --cnt)
     117  	{
     118  	  iov[cnt].iov_base = (char *) list->str;
     119  	  iov[cnt].iov_len = list->len;
     120  	  total += list->len;
     121  	  list = list->next;
     122  	}
     123  
     124        WRITEV_FOR_FATAL (fd, iov, nlist, total);
     125  
     126        total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
     127        struct abort_msg_s *buf = __mmap (NULL, total,
     128  					PROT_READ | PROT_WRITE,
     129  					MAP_ANON | MAP_PRIVATE, -1, 0);
     130        if (__glibc_likely (buf != MAP_FAILED))
     131  	{
     132  	  buf->size = total;
     133  	  char *wp = buf->msg;
     134  	  for (int cnt = 0; cnt < nlist; ++cnt)
     135  	    wp = mempcpy (wp, iov[cnt].iov_base, iov[cnt].iov_len);
     136  	  *wp = '\0';
     137  
     138  	  /* We have to free the old buffer since the application might
     139  	     catch the SIGABRT signal.  */
     140  	  struct abort_msg_s *old = atomic_exchange_acquire (&__abort_msg,
     141  							     buf);
     142  	  if (old != NULL)
     143  	    __munmap (old, old->size);
     144  	}
     145      }
     146  
     147    va_end (ap);
     148  
     149    /* Kill the application.  */
     150    abort ();
     151  }
     152  
     153  
     154  void
     155  __libc_fatal (const char *message)
     156  {
     157    /* The loop is added only to keep gcc happy.  */
     158    while (1)
     159      __libc_message ("%s", message);
     160  }
     161  libc_hidden_def (__libc_fatal)