* lib/error.c: Merge changes since 2018 from glibc. ----- The following changes are taken from glibc: (__error_internal, __error_at_line_internal): New functions, with most of the old error and error_at_line_internal but with va_list and with a new trailing mode_args, for wide character mode. (error_tail): Add trailing arg. (error_tail, __error_internal, __error_at_line_internal): Redo _LIBC implementation with respect to cancelation. [_LIBC]: Include <libc-lock.h>, not <bits/libc-lock.h>. ----- The following changes are specific to Gnulib: (__error_internal, __error_at_line_internal, error_tail) [!_LIBC]: Use macros to define away the new trailing arg, and to name the internal functions to verror and verror_at_line. (verror, verror_at_line) [!_LIBC]: Undef so that we omit the __gl_error_call business when defining these functions. * lib/error.in.h: Include stdarg.h. (verror, verror_at_line): New decls and macros. * m4/error_h.m4 ([gl_ERROR_H]): Always compile error.c if the verror module is also present. * modules/verror (Files, lib_SOURCES): Remove lib/verror.h, lib/verror.c. (Depends-on): Remove stdio, xvasprintf. (configure.ac-early): Define gl_HAVE_MODULE_VERROR so that the error module compiles error.c. Not sure if this is the standard way to do this, but it seems to work. * modules/verror (Include), tests/test-verror.c: Include error.h, not verror.h. --- ChangeLog | 30 ++++++++ NEWS | 3 + lib/error.c | 166 +++++++++++++++++--------------------------- lib/error.in.h | 31 +++++++++ lib/verror.c | 80 --------------------- lib/verror.h | 62 ----------------- m4/error_h.m4 | 17 +++-- modules/verror | 10 ++- tests/test-verror.c | 2 +- 9 files changed, 143 insertions(+), 258 deletions(-) delete mode 100644 lib/verror.c delete mode 100644 lib/verror.h
diff --git a/ChangeLog b/ChangeLog index bd5e7b1ce5..fe16aa1787 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,35 @@ 2024-08-14 Paul Eggert <egg...@cs.ucla.edu> + error: merge from glibc and with verror + * lib/error.c: Merge changes since 2018 from glibc. + ----- The following changes are taken from glibc: + (__error_internal, __error_at_line_internal): New functions, + with most of the old error and error_at_line_internal but + with va_list and with a new trailing mode_args, + for wide character mode. + (error_tail): Add trailing arg. + (error_tail, __error_internal, __error_at_line_internal): + Redo _LIBC implementation with respect to cancelation. + [_LIBC]: Include <libc-lock.h>, not <bits/libc-lock.h>. + ----- The following changes are specific to Gnulib: + (__error_internal, __error_at_line_internal, error_tail) [!_LIBC]: + Use macros to define away the new trailing arg, and to name + the internal functions to verror and verror_at_line. + (verror, verror_at_line) [!_LIBC]: Undef so that we omit + the __gl_error_call business when defining these functions. + * lib/error.in.h: Include stdarg.h. + (verror, verror_at_line): New decls and macros. + * m4/error_h.m4 ([gl_ERROR_H]): Always compile error.c if + the verror module is also present. + * modules/verror (Files, lib_SOURCES): + Remove lib/verror.h, lib/verror.c. + (Depends-on): Remove stdio, xvasprintf. + (configure.ac-early): Define gl_HAVE_MODULE_VERROR so that + the error module compiles error.c. Not sure if this is the + standard way to do this, but it seems to work. + * modules/verror (Include), tests/test-verror.c: + Include error.h, not verror.h. + error: it’s cold This mimics what glibc is doing nowadays. * lib/error.in.h (error, error_at_line): diff --git a/NEWS b/NEWS index 865b86ba3c..40a8da647a 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,9 @@ User visible incompatible changes Date Modules Changes +2024-08-14 verror The include file is changed from "verror.h" + to <error.h>. + 2024-08-09 full-read These modules now prefer signed types to size_t. full-write The preferred types are idx_t for object sizes and safe-read ptrdiff_t for values that are either a size or -1. diff --git a/lib/error.c b/lib/error.c index c53dfeb60d..843e19304e 100644 --- a/lib/error.c +++ b/lib/error.c @@ -1,25 +1,32 @@ /* Error handler for noninteractive utilities - Copyright (C) 1990-1998, 2000-2007, 2009-2024 Free Software Foundation, Inc. + Copyright (C) 1990-2024 Free Software Foundation, Inc. This file is part of the GNU C Library. - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This file is distributed in the hope that it will be useful, + The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. */ + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ /* Written by David MacKenzie <d...@gnu.ai.mit.edu>. */ #if !_LIBC # include <config.h> # define _GL_NO_INLINE_ERROR +# define __error_internal(status, err, fmt, args, flags) \ + verror (status, err, fmt, args) +# define __error_at_line_internal(status, err, file, line, fmt, args, flags) \ + verror_at_line (status, err, file, line, fmt, args) +# define error_tail(status, err, fmt, args, flags) \ + error_tail (status, err, fmt, args) #endif #include <error.h> @@ -85,7 +92,7 @@ extern void __error_at_line (int status, int errnum, const char *file_name, # undef putc # define putc(c, fp) _IO_putc (c, fp) -# include <bits/libc-lock.h> +# include <libc-lock.h> #else /* not _LIBC */ @@ -123,6 +130,9 @@ int strerror_r (int errnum, char *buf, size_t buflen); # if GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r # define __strerror_r strerror_r # endif /* GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r */ + +# undef verror +# undef verror_at_line #endif /* not _LIBC */ #if !_LIBC @@ -202,75 +212,19 @@ print_errno_message (int errnum) } static void _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0) _GL_ARG_NONNULL ((3)) -error_tail (int status, int errnum, const char *message, va_list args) +error_tail (int status, int errnum, const char *message, va_list args, + unsigned int mode_flags) { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - { - size_t len = strlen (message) + 1; - wchar_t *wmessage = NULL; - mbstate_t st; - size_t res; - const char *tmp; - bool use_malloc = false; - - while (1) - { - if (__libc_use_alloca (len * sizeof (wchar_t))) - wmessage = (wchar_t *) alloca (len * sizeof (wchar_t)); - else - { - if (!use_malloc) - wmessage = NULL; - - wchar_t *p = (wchar_t *) realloc (wmessage, - len * sizeof (wchar_t)); - if (p == NULL) - { - free (wmessage); - fputws_unlocked (L"out of memory\n", stderr); - return; - } - wmessage = p; - use_malloc = true; - } - - memset (&st, '\0', sizeof (st)); - tmp = message; - - res = mbsrtowcs (wmessage, &tmp, len, &st); - if (res != len) - break; - - if (__builtin_expect (len >= SIZE_MAX / sizeof (wchar_t) / 2, 0)) - { - /* This really should not happen if everything is fine. */ - res = (size_t) -1; - break; - } - - len *= 2; - } - - if (res == (size_t) -1) - { - /* The string cannot be converted. */ - if (use_malloc) - { - free (wmessage); - use_malloc = false; - } - wmessage = (wchar_t *) L"???"; - } - - __vfwprintf (stderr, wmessage, args); - - if (use_malloc) - free (wmessage); - } - else + int ret = __vfxprintf (stderr, message, args, mode_flags); + if (ret < 0 && errno == ENOMEM && _IO_fwide (stderr, 0) > 0) + /* Leave a trace in case the heap allocation of the message string + failed. */ + fputws_unlocked (L"out of memory\n", stderr); +#else + vfprintf (stderr, message, args); #endif - vfprintf (stderr, message, args); + va_end (args); ++error_message_count; if (errnum) @@ -291,16 +245,14 @@ error_tail (int status, int errnum, const char *message, va_list args) If ERRNUM is nonzero, print its corresponding system error message. Exit with status STATUS if it is nonzero. */ void -error (int status, int errnum, const char *message, ...) +__error_internal (int status, int errnum, const char *message, + va_list args, unsigned int mode_flags) { - va_list args; - -#if defined _LIBC && defined __libc_ptf_call +#if defined _LIBC /* We do not want this call to be cut short by a thread cancellation. Therefore disable cancellation for now. */ int state = PTHREAD_CANCEL_ENABLE; - __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), - 0); + __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state); #endif flush_stdout (); @@ -318,28 +270,32 @@ error (int status, int errnum, const char *message, ...) #endif } - va_start (args, message); - error_tail (status, errnum, message, args); - va_end (args); + error_tail (status, errnum, message, args, mode_flags); #ifdef _LIBC _IO_funlockfile (stderr); -# ifdef __libc_ptf_call - __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); -# endif + __pthread_setcancelstate (state, NULL); #endif } + +void +error (int status, int errnum, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + __error_internal (status, errnum, message, ap, 0); + va_end (ap); +} /* Sometimes we want to have at most one error per line. This variable controls whether this mode is selected or not. */ int error_one_per_line; void -error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, ...) +__error_at_line_internal (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, + va_list args, unsigned int mode_flags) { - va_list args; - if (error_one_per_line) { static const char *old_file_name; @@ -358,12 +314,11 @@ error_at_line (int status, int errnum, const char *file_name, old_line_number = line_number; } -#if defined _LIBC && defined __libc_ptf_call +#if defined _LIBC /* We do not want this call to be cut short by a thread cancellation. Therefore disable cancellation for now. */ int state = PTHREAD_CANCEL_ENABLE; - __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), - 0); + __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state); #endif flush_stdout (); @@ -389,18 +344,25 @@ error_at_line (int status, int errnum, const char *file_name, file_name, line_number); #endif - va_start (args, message); - error_tail (status, errnum, message, args); - va_end (args); + error_tail (status, errnum, message, args, mode_flags); #ifdef _LIBC _IO_funlockfile (stderr); -# ifdef __libc_ptf_call - __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); -# endif + __pthread_setcancelstate (state, NULL); #endif } +void +error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + __error_at_line_internal (status, errnum, file_name, line_number, + message, ap, 0); + va_end (ap); +} + #ifdef _LIBC /* Make the weak alias. */ # undef error diff --git a/lib/error.in.h b/lib/error.in.h index d2aede7d53..82022a9362 100644 --- a/lib/error.in.h +++ b/lib/error.in.h @@ -36,6 +36,9 @@ #error "Please include config.h first." #endif +/* Get va_list. */ +#include <stdarg.h> + /* Get 'unreachable'. */ #include <stddef.h> @@ -200,6 +203,34 @@ _gl_inline_error_at_line (int __status, int __errnum, const char *__filename, #endif _GL_CXXALIASWARN (error_at_line); +/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)'; + if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). + If STATUS is nonzero, terminate the program with 'exit (STATUS)'. + Use the globals error_print_progname and error_message_count similarly + to error(). */ + +extern void verror (int __status, int __errnum, const char *__format, + va_list __args) + _GL_ATTRIBUTE_COLD + _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 3, 0)); +#define verror(status, ...) \ + __gl_error_call (verror, status, __VA_ARGS__) + +/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)'; + if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). + If STATUS is nonzero, terminate the program with 'exit (STATUS)'. + If FNAME is not NULL, prepend the message with "FNAME:LINENO:". + Use the globals error_print_progname, error_message_count, and + error_one_per_line similarly to error_at_line(). */ + +extern void verror_at_line (int __status, int __errnum, const char *__fname, + unsigned int __lineno, const char *__format, + va_list __args) + _GL_ATTRIBUTE_COLD + _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 5, 0)); +#define verror_at_line(status, ...) \ + __gl_error_call (verror_at_line, status, __VA_ARGS__) + /* If NULL, error will flush stdout, then print on stderr the program name, a colon and a space. Otherwise, error will call this function without parameters instead. */ diff --git a/lib/verror.c b/lib/verror.c deleted file mode 100644 index 69f606c0a4..0000000000 --- a/lib/verror.c +++ /dev/null @@ -1,80 +0,0 @@ -/* va_list error handler for noninteractive utilities - Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. */ - -/* Written by Eric Blake. */ - -#include <config.h> - -/* Specification. */ -#include "verror.h" - -#include <errno.h> -#include <stdarg.h> -#include <stdlib.h> - -#include <error.h> -#include "xvasprintf.h" - -#if ENABLE_NLS -# include "gettext.h" -# define _(msgid) gettext (msgid) -#endif - -#ifndef _ -# define _(String) String -#endif - -/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)'; - if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). - If STATUS is nonzero, terminate the program with 'exit (STATUS)'. - Use the globals error_print_progname and error_message_count similarly - to error(). */ -void -verror (int status, int errnum, const char *format, va_list args) -{ - verror_at_line (status, errnum, NULL, 0, format, args); -} - -/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)'; - if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). - If STATUS is nonzero, terminate the program with 'exit (STATUS)'. - If FNAME is not NULL, prepend the message with "FNAME:LINENO:". - Use the globals error_print_progname, error_message_count, and - error_one_per_line similarly to error_at_line(). */ -void -verror_at_line (int status, int errnum, const char *file, - unsigned int line_number, const char *format, va_list args) -{ - char *message = xvasprintf (format, args); - if (message) - { - /* Until https://sourceware.org/bugzilla/show_bug.cgi?id=2997 is fixed, - glibc violates GNU Coding Standards when the file argument to - error_at_line is NULL. */ - if (file) - error_at_line (status, errnum, file, line_number, "%s", message); - else - error (status, errnum, "%s", message); - } - else - { - /* EOVERFLOW, EINVAL, and EILSEQ from xvasprintf are signs of - serious programmer errors. */ - error (0, errno, _("unable to display error message")); - abort (); - } - free (message); -} diff --git a/lib/verror.h b/lib/verror.h deleted file mode 100644 index a951a5c3e1..0000000000 --- a/lib/verror.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Declaration for va_list error-reporting function - Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. */ - -#ifndef _VERROR_H -#define _VERROR_H 1 - -/* This file uses _GL_ATTRIBUTE_COLD, _GL_ATTRIBUTE_FORMAT. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include <stdarg.h> - -/* Get _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD. */ -#include <stdio.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)'; - if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). - If STATUS is nonzero, terminate the program with 'exit (STATUS)'. - Use the globals error_print_progname and error_message_count similarly - to error(). */ - -extern void verror (int __status, int __errnum, const char *__format, - va_list __args) - _GL_ATTRIBUTE_COLD - _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 3, 0)); - -/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)'; - if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). - If STATUS is nonzero, terminate the program with 'exit (STATUS)'. - If FNAME is not NULL, prepend the message with "FNAME:LINENO:". - Use the globals error_print_progname, error_message_count, and - error_one_per_line similarly to error_at_line(). */ - -extern void verror_at_line (int __status, int __errnum, const char *__fname, - unsigned int __lineno, const char *__format, - va_list __args) - _GL_ATTRIBUTE_COLD - _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 5, 0)); - -#ifdef __cplusplus -} -#endif - -#endif /* verror.h */ diff --git a/m4/error_h.m4 b/m4/error_h.m4 index 050a410ce4..91a8fc6897 100644 --- a/m4/error_h.m4 +++ b/m4/error_h.m4 @@ -1,5 +1,5 @@ # error_h.m4 -# serial 4 +# serial 5 dnl Copyright (C) 1996-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -111,12 +111,15 @@ AC_DEFUN_ONCE([gl_ERROR_H], esac fi - if test $HAVE_ERROR = 0 || test $REPLACE_ERROR = 1 \ - || test $HAVE_ERROR_AT_LINE = 0 || test $REPLACE_ERROR_AT_LINE = 1; then - COMPILE_ERROR_C=1 - else - COMPILE_ERROR_C=0 - fi + m4_ifdef([gl_HAVE_MODULE_VERROR], + [COMPILE_ERROR_C=1], + [if test $HAVE_ERROR = 0 || test $REPLACE_ERROR = 1 \ + || test $HAVE_ERROR_AT_LINE = 0 \ + || test $REPLACE_ERROR_AT_LINE = 1; then + COMPILE_ERROR_C=1 + else + COMPILE_ERROR_C=0 + fi]) AC_SUBST([HAVE_ERROR]) AC_SUBST([HAVE_ERROR_AT_LINE]) diff --git a/modules/verror b/modules/verror index 16ad0c5961..8fea49ad3c 100644 --- a/modules/verror +++ b/modules/verror @@ -2,13 +2,12 @@ Description: verror and verror_at_line functions: Error reporting with va_list. Files: -lib/verror.h -lib/verror.c Depends-on: -stdio error -xvasprintf + +configure.ac-early: +AC_DEFUN([gl_HAVE_MODULE_VERROR]) configure.ac: m4_ifdef([AM_XGETTEXT_OPTION], @@ -16,10 +15,9 @@ m4_ifdef([AM_XGETTEXT_OPTION], AM_][XGETTEXT_OPTION([--flag=verror_at_line:5:c-format])]) Makefile.am: -lib_SOURCES += verror.h verror.c Include: -"verror.h" +<error.h> License: GPL diff --git a/tests/test-verror.c b/tests/test-verror.c index 1e9dcd9cc5..bd17cc1429 100644 --- a/tests/test-verror.c +++ b/tests/test-verror.c @@ -18,7 +18,7 @@ #include <config.h> -#include "verror.h" +#include <error.h> #include <errno.h> #include <stdarg.h> -- 2.46.0