mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-03 20:53:13 +03:00 
			
		
		
		
	assert: Refactor assert/assert_perror
It now calls __libc_assert, which contains similar logic. The assert call only requires memory allocation for the message translation, so test-assert2.c is adapted to handle it. It also removes the fxprintf from assert/assert_perror; although it is not 100% backwards-compatible (write message only if there is a file descriptor associated with the stderr). It now writes bytes directly without going through the wide stream state. Checked on aarch64-linux-gnu. Reviewed-by: Florian Weimer <fweimer@redhat.com>
This commit is contained in:
		@@ -28,6 +28,7 @@ __libc_assert_fail (const char *assertion, const char *file, unsigned int line,
 | 
			
		||||
  char linebuf[INT_BUFSIZE_BOUND (unsigned int)];
 | 
			
		||||
  array_end (linebuf)[-1] = '\0';
 | 
			
		||||
  char *linestr = _itoa_word (line, array_end (linebuf) - 1, 10, 0);
 | 
			
		||||
  __libc_message ("Fatal glibc error: %s:%s (%s): assertion failed: %s\n",
 | 
			
		||||
                  file, linestr, function, assertion);
 | 
			
		||||
  __libc_assert (
 | 
			
		||||
      "Fatal glibc error: %s:%s (%s): assertion failed: %s\n", file, linestr,
 | 
			
		||||
      function, assertion);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,15 @@
 | 
			
		||||
   License along with the GNU C Library; if not, see
 | 
			
		||||
   <https://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
#include <_itoa.h>
 | 
			
		||||
#include <array_length.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <intprops.h>
 | 
			
		||||
#include <libintl.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
extern const char *__progname;
 | 
			
		||||
 | 
			
		||||
/* This function, when passed an error number, a filename, and a line
 | 
			
		||||
   number, prints a message on the standard error stream of the form:
 | 
			
		||||
@@ -31,8 +36,19 @@ __assert_perror_fail (int errnum,
 | 
			
		||||
{
 | 
			
		||||
  char errbuf[1024];
 | 
			
		||||
 | 
			
		||||
  char *e = __strerror_r (errnum, errbuf, sizeof errbuf);
 | 
			
		||||
  __assert_fail_base (_("%s%s%s:%u: %s%sUnexpected error: %s.\n"),
 | 
			
		||||
		      e, file, line, function);
 | 
			
		||||
  const char *e = __strerror_r (errnum, errbuf, sizeof errbuf);
 | 
			
		||||
 | 
			
		||||
  char linebuf[INT_BUFSIZE_BOUND (unsigned int)];
 | 
			
		||||
  array_end (linebuf)[-1] = '\0';
 | 
			
		||||
  char *linestr = _itoa_word (line, array_end (linebuf) - 1, 10, 0);
 | 
			
		||||
 | 
			
		||||
  __libc_message (_("%s%s%s:%s: %s%sUnexpected error: %s.\n"),
 | 
			
		||||
		  __progname,
 | 
			
		||||
		  __progname[0] ? ": " : "",
 | 
			
		||||
		  file,
 | 
			
		||||
		  linestr,
 | 
			
		||||
		  function ? function : "",
 | 
			
		||||
		  function ? ": " : "",
 | 
			
		||||
		  e);
 | 
			
		||||
}
 | 
			
		||||
libc_hidden_def (__assert_perror_fail)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										112
									
								
								assert/assert.c
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								assert/assert.c
									
									
									
									
									
								
							@@ -15,115 +15,31 @@
 | 
			
		||||
   License along with the GNU C Library; if not, see
 | 
			
		||||
   <https://www.gnu.org/licenses/>.  */
 | 
			
		||||
 | 
			
		||||
#include <array_length.h>
 | 
			
		||||
#include <intprops.h>
 | 
			
		||||
#include <ldsodefs.h>
 | 
			
		||||
#include <libc-pointer-arith.h>
 | 
			
		||||
#include <libintl.h>
 | 
			
		||||
#include <libio/iolibio.h>
 | 
			
		||||
#include <setvmaname.h>
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern const char *__progname;
 | 
			
		||||
 | 
			
		||||
#define fflush(s) _IO_fflush (s)
 | 
			
		||||
 | 
			
		||||
/* This function, when passed a string containing an asserted
 | 
			
		||||
   expression, a filename, and a line number, prints a message
 | 
			
		||||
   on the standard error stream of the form:
 | 
			
		||||
	a.c:10: foobar: Assertion `a == b' failed.
 | 
			
		||||
   It then aborts program execution via a call to `abort'.  */
 | 
			
		||||
 | 
			
		||||
#ifdef FATAL_PREPARE_INCLUDE
 | 
			
		||||
# include FATAL_PREPARE_INCLUDE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
__assert_fail_base (const char *fmt, const char *assertion, const char *file,
 | 
			
		||||
		    unsigned int line, const char *function)
 | 
			
		||||
{
 | 
			
		||||
  char *str;
 | 
			
		||||
 | 
			
		||||
#ifdef FATAL_PREPARE
 | 
			
		||||
  FATAL_PREPARE;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  int total = __asprintf (&str, fmt,
 | 
			
		||||
			  __progname, __progname[0] ? ": " : "",
 | 
			
		||||
			  file, line,
 | 
			
		||||
			  function ? function : "", function ? ": " : "",
 | 
			
		||||
			  assertion);
 | 
			
		||||
  if (total >= 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* Print the message.  */
 | 
			
		||||
      (void) __fxprintf (NULL, "%s", str);
 | 
			
		||||
      (void) fflush (stderr);
 | 
			
		||||
 | 
			
		||||
      total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
 | 
			
		||||
			GLRO(dl_pagesize));
 | 
			
		||||
      struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
 | 
			
		||||
					MAP_ANON | MAP_PRIVATE, -1, 0);
 | 
			
		||||
      if (__glibc_likely (buf != MAP_FAILED))
 | 
			
		||||
	{
 | 
			
		||||
	  buf->size = total;
 | 
			
		||||
	  strcpy (buf->msg, str);
 | 
			
		||||
	  __set_vma_name (buf, total, " glibc: assert");
 | 
			
		||||
 | 
			
		||||
	  /* We have to free the old buffer since the application might
 | 
			
		||||
	     catch the SIGABRT signal.  */
 | 
			
		||||
	  struct abort_msg_s *old = atomic_exchange_acquire (&__abort_msg, buf);
 | 
			
		||||
 | 
			
		||||
	  if (old != NULL)
 | 
			
		||||
	    __munmap (old, old->size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      free (str);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* At least print a minimal message.  */
 | 
			
		||||
      char linebuf[INT_STRLEN_BOUND (int) + sizeof ":: "];
 | 
			
		||||
      struct iovec v[9];
 | 
			
		||||
      int i = 0;
 | 
			
		||||
 | 
			
		||||
#define WS(s) (v[i].iov_len = strlen (v[i].iov_base = (void *) (s)), i++)
 | 
			
		||||
 | 
			
		||||
      if (__progname)
 | 
			
		||||
	{
 | 
			
		||||
	  WS (__progname);
 | 
			
		||||
	  WS (": ");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      WS (file);
 | 
			
		||||
      v[i++] = (struct iovec) {.iov_base = linebuf,
 | 
			
		||||
	.iov_len = sprintf (linebuf, ":%d: ", line)};
 | 
			
		||||
 | 
			
		||||
      if (function)
 | 
			
		||||
	{
 | 
			
		||||
	  WS (function);
 | 
			
		||||
	  WS (": ");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      WS ("Assertion `");
 | 
			
		||||
      WS (assertion);
 | 
			
		||||
      /* We omit the '.' here so that the assert tests can tell when
 | 
			
		||||
         this code path is taken.  */
 | 
			
		||||
      WS ("' failed\n");
 | 
			
		||||
 | 
			
		||||
      (void) __writev (STDERR_FILENO, v, i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  abort ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#undef __assert_fail
 | 
			
		||||
void
 | 
			
		||||
__assert_fail (const char *assertion, const char *file, unsigned int line,
 | 
			
		||||
	       const char *function)
 | 
			
		||||
{
 | 
			
		||||
  __assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n"),
 | 
			
		||||
		      assertion, file, line, function);
 | 
			
		||||
  char linebuf[INT_BUFSIZE_BOUND (unsigned int)];
 | 
			
		||||
  array_end (linebuf)[-1] = '\0';
 | 
			
		||||
  char *linestr = _itoa_word (line, array_end (linebuf) - 1, 10, 0);
 | 
			
		||||
 | 
			
		||||
  __libc_assert (_("%s%s%s:%s: %s%sAssertion `%s' failed.\n"),
 | 
			
		||||
		 __progname,
 | 
			
		||||
		 __progname[0] ? ": " : "",
 | 
			
		||||
		 file,
 | 
			
		||||
		 linestr,
 | 
			
		||||
		 function ? function : "",
 | 
			
		||||
		 function ? ": " : "",
 | 
			
		||||
		 assertion);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -127,7 +127,7 @@ check_posix (const char *buf, int rv, int line,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
one_test (void (*func)(void *), int which_path)
 | 
			
		||||
one_test (void (*func)(void *))
 | 
			
		||||
{
 | 
			
		||||
  struct support_capture_subprocess sp;
 | 
			
		||||
  int rv;
 | 
			
		||||
@@ -140,17 +140,7 @@ one_test (void (*func)(void *), int which_path)
 | 
			
		||||
 | 
			
		||||
  check_posix (sp.err.buffer, rv, do_lineno, do_funcname, "1 == 2");
 | 
			
		||||
 | 
			
		||||
  /* Look for intentional subtle differences in messages to verify
 | 
			
		||||
     that the intended code path was taken.  */
 | 
			
		||||
  switch (which_path)
 | 
			
		||||
    {
 | 
			
		||||
    case 0:
 | 
			
		||||
      TEST_VERIFY (strstr (sp.err.buffer, "failed.\n") != NULL);
 | 
			
		||||
      break;
 | 
			
		||||
    case 1:
 | 
			
		||||
      TEST_VERIFY (strstr (sp.err.buffer, "failed\n") != NULL);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  TEST_VERIFY (strstr (sp.err.buffer, "failed.\n") != NULL);
 | 
			
		||||
 | 
			
		||||
  support_capture_subprocess_free (&sp);
 | 
			
		||||
}
 | 
			
		||||
@@ -158,8 +148,8 @@ one_test (void (*func)(void *), int which_path)
 | 
			
		||||
static int
 | 
			
		||||
do_test(void)
 | 
			
		||||
{
 | 
			
		||||
  one_test (test_assert_normal, 0);
 | 
			
		||||
  one_test (test_assert_nomalloc, 1);
 | 
			
		||||
  one_test (test_assert_normal);
 | 
			
		||||
  one_test (test_assert_nomalloc);
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -171,36 +171,35 @@ extern void __fortify_fail (const char *msg) __attribute__ ((__noreturn__));
 | 
			
		||||
libc_hidden_proto (__fortify_fail)
 | 
			
		||||
 | 
			
		||||
/* The maximum number of varargs allowed in a __libc_message format string */
 | 
			
		||||
#define LIBC_MESSAGE_MAX_ARGS 4
 | 
			
		||||
#define LIBC_MESSAGE_MAX_ARGS 7
 | 
			
		||||
 | 
			
		||||
#define IOVEC_MAX_ERR_MSG "Fatal glibc error: Internal " \
 | 
			
		||||
			  "__libc_message error. Too many arguments.\n"
 | 
			
		||||
#define IOVEC_MAX_ERR_MSG_LEN (sizeof (IOVEC_MAX_ERR_MSG) - 1)
 | 
			
		||||
 | 
			
		||||
_Noreturn void __libc_message_impl (const char *__fnt, ...) attribute_hidden
 | 
			
		||||
     __attribute__ ((__format__ (__printf__, 1, 2)));
 | 
			
		||||
_Noreturn void __libc_message_impl (const char *__vmaname, const char *__fmt,
 | 
			
		||||
				    ...) attribute_hidden
 | 
			
		||||
     __attribute__ ((__format__ (__printf__, 2, 3)));
 | 
			
		||||
 | 
			
		||||
#define __libc_message0(fmt) \
 | 
			
		||||
   __libc_message_impl (fmt)
 | 
			
		||||
#define __libc_message1(fmt, a1) \
 | 
			
		||||
   __libc_message_impl (fmt, a1)
 | 
			
		||||
#define __libc_message2(fmt, a1, a2) \
 | 
			
		||||
   __libc_message_impl (fmt, a1, a2)
 | 
			
		||||
#define __libc_message3(fmt, a1, a2, a3) \
 | 
			
		||||
   __libc_message_impl (fmt, a1, a2, a3)
 | 
			
		||||
#define __libc_message4(fmt, a1, a2, a3, a4) \
 | 
			
		||||
   __libc_message_impl (fmt, a1, a2, a3, a4)
 | 
			
		||||
#define __libc_fatal_vma_name  "glibc: fatal"
 | 
			
		||||
#define __libc_assert_vma_name "glibc: assert"
 | 
			
		||||
 | 
			
		||||
#define __libc_message_concat_x(a,b)  a##b
 | 
			
		||||
#define __libc_message_concat(a,b)    __libc_message_concat_x (a, b)
 | 
			
		||||
 | 
			
		||||
#define __libc_message_nargs_x(a0,a1,a2,a3,a4,a5,a6,...) a6
 | 
			
		||||
#define __libc_message_nargs(b, ...) \
 | 
			
		||||
   __libc_message_nargs_x (__VA_ARGS__,6,5,4,3,2,1,0,)
 | 
			
		||||
#define __libc_message_disp(b, ...) \
 | 
			
		||||
   __libc_message_concat (b, __libc_message_nargs (__VA_ARGS__))(__VA_ARGS__)
 | 
			
		||||
static inline _Noreturn void __libc_message_wrapper (const char *vmaname,
 | 
			
		||||
						     const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __va_arg_pack_len
 | 
			
		||||
  if (__va_arg_pack_len () > LIBC_MESSAGE_MAX_ARGS)
 | 
			
		||||
    {
 | 
			
		||||
      __errordecl (__libc_message_error, "invalid number of arguments");
 | 
			
		||||
      __libc_message_error ();
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
  __libc_message_impl (vmaname, fmt, __va_arg_pack ());
 | 
			
		||||
}
 | 
			
		||||
#define __libc_message(...) \
 | 
			
		||||
   __libc_message_disp (__libc_message, __VA_ARGS__)
 | 
			
		||||
   __libc_message_wrapper (__libc_fatal_vma_name, __VA_ARGS__)
 | 
			
		||||
#define __libc_assert(...) \
 | 
			
		||||
   __libc_message_wrapper (__libc_assert_vma_name, __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
/* Acquire ownership of STREAM.  */
 | 
			
		||||
extern void __flockfile (FILE *__stream) attribute_hidden;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,11 @@
 | 
			
		||||
static _Noreturn void
 | 
			
		||||
run_libc_message (void *closure)
 | 
			
		||||
{
 | 
			
		||||
  /* We only support 4 arguments.  Call with 5 to trigger failure.  */
 | 
			
		||||
  __libc_message_impl ("%s %s %s %s %s\n", "1", "2", "3", "4", "5");
 | 
			
		||||
  /* We only support 7 (LIBC_MESSAGE_MAX_ARGS) arguments.  Call with 8 to
 | 
			
		||||
     trigger failure.  */
 | 
			
		||||
  __libc_message_impl ("glibc: test",
 | 
			
		||||
		       "%s %s %s %s %s %s %s %s\n",
 | 
			
		||||
		       "1", "2", "3", "4", "5", "6", "7", "8");
 | 
			
		||||
  __builtin_unreachable ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total)
 | 
			
		||||
 | 
			
		||||
/* Abort with an error message.  */
 | 
			
		||||
void
 | 
			
		||||
__libc_message_impl (const char *fmt, ...)
 | 
			
		||||
__libc_message_impl (const char *vma_name, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list ap;
 | 
			
		||||
  int fd = -1;
 | 
			
		||||
@@ -123,7 +123,7 @@ __libc_message_impl (const char *fmt, ...)
 | 
			
		||||
	    wp = mempcpy (wp, iov[cnt].iov_base, iov[cnt].iov_len);
 | 
			
		||||
	  *wp = '\0';
 | 
			
		||||
 | 
			
		||||
	  __set_vma_name (buf, total, " glibc: fatal");
 | 
			
		||||
	  __set_vma_name (buf, total, vma_name);
 | 
			
		||||
 | 
			
		||||
	  /* We have to free the old buffer since the application might
 | 
			
		||||
	     catch the SIGABRT signal.  */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user