126 files changed, 3185 insertions, 346 deletions
@@ -1,3 +1,508 @@ +2021-03-03 Bruno Haible <bruno@clisp.org> + + asyncsafe-spin, simple-atomic: Add support for tcc/x86. + * lib/asyncsafe-spin.c (memory_barrier): With tcc/x86, don't use the + 'mfence' instruction. + * lib/simple-atomic.c (memory_barrier): Likewise. + + asyncsafe-spin, simple-atomic: Add support for tcc. + * lib/asyncsafe-spin.c (memory_barrier, atomic_compare_and_swap): On + i386 and x86_64, treat tcc like older GCC or clang. + * lib/simple-atomic.c (memory_barrier, atomic_compare_and_swap, + atomic_compare_and_swap_ptr): Likewise. + +2021-03-02 Bruno Haible <bruno@clisp.org> + + stddef: Work around an interoperability problem of tcc with glibc. + Reported by Luca Saiu <positron@gnu.org> in + <https://lists.gnu.org/archive/html/bug-gnulib/2021-03/msg00011.html>. + * lib/stddef.in.h [__TINYC__]: In case of the special invocation + convention, undefine the macros that TinyCC's <stddef.h> should undefine + but doesn't. + * doc/posix-headers/stddef.texi: Mention the TinyCC bug. + +2021-03-02 Paul Eggert <eggert@cs.ucla.edu> + + mbrtowc: port to AIX 7.1 with xlc 12.1 + Fix a problem with locks when building GNU Tar (Savannah commit + 55f2a0772e08b9febac3ac0de5cb048d4c60d2f5) on AIX 7.1 with IBM XL + C/C++ V12.1 using ‘./configure CC=xlc’. The link fails due to + missing definitions of pthread_mutex_lock and + pthread_mutex_unlock. GNU Tar uses unlocked-io and so + should not need to worry about multithreading or locks. + * lib/mbtowc-lock.h (mbtowc_with_lock) [USE_UNLOCKED_IO]: + Don’t bother with locks, since this app is single-threaded. + There may be similar linking problems with lib/nl_langinfo.c and + lib/setlocale_null.c but my GNU Tar build didn’t run into them, so + I left them alone for now. + +2021-03-01 Paul Eggert <eggert@cs.ucla.edu> + + unlocked-io: do not redefine getc_unlocked etc. + I ran into this problem on AIX 7.1 with GNU Tar, which + enables visibility of getc_unlocked etc. after testing + whether they’re declared, causing argp-namefrob.h and + unlocked-io.h to redefine the macros. + * lib/argp-namefrob.h, lib/unlocked-io.h: + (clearerr_unlocked, feof_unlocked ferror_unlocked) + (fflush_unlocked, fgets_unlocked, fputc_unlocked, fputs_unlocked) + (fread_unlocked, fwrite_unlocked, getc_unlocked, getchar_unlocked) + (putc_unlocked, putchar_unlocked): Do not define if already defined. + + parse-datetime2: new module + This splits the old parse-datetime into two parts; the + first is parse-datetime2 which supports all the new bells + and whistles, the second is parse-datetime, which reverts to + its original intent. This avoids some bogus diagnostics + when build GNU Tar with gcc -flto -fanalyze and + with --enable-gcc-warnings. And it slims down the + executable a bit. + * NEWS: Mention this. + * lib/parse-datetime.y (parser_control) [!GNULIB_PARSE_DATETIME2]: + Omit parse_datetime_debug member. + (debugging): New function. Use it everywhere the old code + would load parse_datetime_debug. + (parse_datetime_body): New static function, with the body + of the old parse_datetime2. Set pc.parse_datetime_debug + only if GNULIB_PARSE_DATETIME2. + (parse_datetime2, parse_datetime): Use this new function. + (parse_datetime2) [!GNULIB_PARSE_DATETIME2]: Remove. + * modules/parse-datetime2: New file. + +2021-02-27 Bruno Haible <bruno@clisp.org> + + string-buffer: Fixes. + * modules/string-buffer (License): Change to LGPL. + * tests/test-string-buffer.c (main): Add another sb_appendf call, that + is more likely to fail. + +2021-02-25 Bernhard Voelker <mail@bernhard-voelker.de> + + gitlog-to-changelog: output SHA in "empty commit message" warning + * build-aux/gitlog-to-changelog: Add $sha to above warning diagnostic. + +2021-02-24 Paul Eggert <eggert@cs.ucla.edu> + + glob: include libc-config.h in a more-standard way + Inspired by Tom Tromey’s report for RHEL 6 in: + https://lists.gnu.org/r/bug-gnulib/2021-02/msg00088.html + * lib/glob.c [!_LIBC]: Include libc-config.h, not just config.h + * lib/glob.in.h: Include libc-config.h only if needed. + +2021-02-21 Bruno Haible <bruno@clisp.org> + + string-buffer: Add tests. + * tests/test-string-buffer.c: New file. + * modules/string-buffer-tests: New file. + + string-buffer: New module. + * lib/string-buffer.h: New file. + * lib/string-buffer.c: New file. + * modules/string-buffer: New file. + * doc/posix-functions/open_memstream.texi: Mention the new module. + +2021-02-21 Bruno Haible <bruno@clisp.org> + + scratch_buffer: Document the exported API. + * lib/scratch_buffer.h: Add comments, taken from + lib/malloc/scratch_buffer.h. + +2021-02-21 Bruno Haible <bruno@clisp.org> + + DEPENDENCIES: Update. + * DEPENDENCIES: Require GCC >= 3.1. Tell where to find working GNU m4 + tarballs. Mention awk. Point to pre-built packages for gettext, bison, + gperf, texinfo. + +2021-02-20 Bruno Haible <bruno@clisp.org> + + parse-datetime: Fix comment. + * modules/parse-datetime (Makefile.am): Fix comment. + +2021-02-16 Bruno Haible <bruno@clisp.org> + + passfd: Fix test failure on FreeBSD >= 12 and NetBSD in 64-bit mode. + * lib/passfd.c (recvfd): Use the CMSG_SPACE macro to compute the value + for msg_controllen. + +2021-02-16 Paul Eggert <eggert@cs.ucla.edu> + + Port better to macOS Mojave + Problem reported by Tom Shields in: + https://lists.gnu.org/r/bug-gnulib/2021-02/msg00064.html + * config/srclist.txt: Comment out dynarray_finalize.c. + * lib/dynarray.h (__libc_dynarray_at_failure): Don’t include + libc-config.h here, as that’s the includer’s responsibility. + * lib/malloc/dynarray_at_failure.c: + * lib/malloc/dynarray_emplace_enlarge.c: + * lib/malloc/dynarray_finalize.c: + * lib/malloc/dynarray_resize.c: + * lib/malloc/dynarray_resize_clear.c: + If _LIBC is not defined, include libc-config.h. + +2021-02-15 Bruno Haible <bruno@clisp.org> + + linked-list test: Add test for SIGNAL_SAFE_LIST. (It currently fails.) + * tests/test-asyncsafe-linked_list.sh: New file. + * tests/test-asyncsafe-linked_list.c: New file. + * modules/linked-list-tests (Files): Add them. + (Depends-on): Add thread, yield, nanosleep, sigaction, sigprocmask. + (Makefile.am): Arrange to compile test-asyncsafe-linked_list.c and run + test-asyncsafe-linked_list.sh. + +2021-02-14 Bruno Haible <bruno@clisp.org> + + simple-atomic: Add tests. + * tests/test-simple-atomic.c: New file. + * modules/simple-atomic-tests: New file. + + simple-atomic: New module. + * lib/simple-atomic.h: New file. + * lib/simple-atomic.c: New file, based on lib/asyncsafe-spin.c. + * modules/simple-atomic: New file. + +2021-02-14 Bruno Haible <bruno@clisp.org> + + Fix distinction of 32-bit/64-bit mode with xlc 13.1.3 on AIX. + * m4/host-cpu-c-abi.m4 (gl_HOST_CPU_C_ABI, gl_HOST_CPU_C_ABI_32BIT): + Test __LP64__ instead of _ARCH_PPC64. + * m4/lib-ld.m4 (AC_LIB_PROG_LD): Likewise. + * lib/stddef.in.h: Likewise. + +2021-02-13 Ozkan Sezer <sezeroz@gmail.com> + + lib-symbol-visibility: Make it work with -Wmissing-prototypes. + * m4/visibility.m4 (gl_VISIBILITY): Avoid error from simultaneous use of + -Wmissing-prototypes and -Werror. + +2021-02-08 Bruno Haible <bruno@clisp.org> + + stddef: Fix test-stddef compilation error on MidnightBSD/x86. + * lib/stddef.in.h (_GL_STDDEF_ALIGNAS, rpl_max_align_t, max_align_t): + Don't ignore HAVE_MAX_ALIGN_T if the compiler is clang. + +2021-02-08 Bruno Haible <bruno@clisp.org> + + Document non-standard prototypes on MidnightBSD. + * doc/posix-functions/initstate.texi: Mention different prototype on + MidnightBSD 2.0. + * doc/posix-functions/srandom.texi: Likewise. + * doc/posix-functions/getlogin_r.texi: Likewise. + * doc/glibc-functions/sethostname.texi: Likewise. + +2021-02-08 Bruno Haible <bruno@clisp.org> + + posixtm tests: Fix warnings seen on MidnightBSD/x86. + * tests/test-posixtm.c (main): Convert two 'time_t' values to 'long' for + printing. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + Add cross-compilation guesses for MidnightBSD. + * m4/malloc.m4 (_AC_FUNC_MALLOC_IF): When cross-compiling, use the + result from native compilation. + * m4/realloc.m4 (_AC_FUNC_REALLOC_IF): Likewise. + * m4/mbrtoc32.m4 (gl_MBRTOC32_SANITYCHECK): Likewise. + * m4/mprotect.m4 (gl_FUNC_MPROTECT_WORKS): Likewise. + * m4/posix_spawn.m4 (gl_POSIX_SPAWN_SECURE): Likewise. + * m4/printf.m4 (gl_PRINTF_SIZES_C99, gl_PRINTF_INFINITE, + gl_PRINTF_INFINITE_LONG_DOUBLE, gl_PRINTF_DIRECTIVE_F, + gl_SNPRINTF_TRUNCATION_C99, gl_SNPRINTF_RETVAL_C99, + gl_SNPRINTF_DIRECTIVE_N, gl_VSNPRINTF_ZEROSIZE_C99): Likewise. + * m4/strfmon_l.m4 (gl_FUNC_STRFMON_L): Likewise. + * m4/setlocale_null.m4 (gl_FUNC_SETLOCALE_NULL): Use predetermined + result on MidnightBSD. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + threadlib: Add support for MidnightBSD. + * m4/threadlib.m4 (gl_WEAK_SYMBOLS, gl_THREADLIB_BODY): On MidnightBSD, + use the same test as on FreeBSD. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + host-os: Add support for MidnightBSD. + * m4/host-os.m4 (gl_HOST_OS): On MidnightBSD, set HOST_OPERATING_SYSTEM + to "MidnightBSD", not "Midnightbsd". + +2021-02-07 Bruno Haible <bruno@clisp.org> + + c-stack: Adjust for MidnightBSD. + * m4/c-stack.m4 (AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC): On MidnightBSD, + set FAULT_YIELDS_SIGBUS. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + relocatable-prog: Add support for MidnightBSD. + * m4/relocatable.m4 (gl_RELOCATABLE_BODY): Use the ELF $ORIGIN trick + also on MidnightBSD >= 1.1. + * build-aux/config.libpath: Treat MidnightBSD like FreeBSD. + * build-aux/reloc-ldflags: Likewise. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + havelib: Add support for MidnightBSD. + * build-aux/config.rpath: Treat MidnightBSD like FreeBSD >= 4. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + wcwidth: Document MidnightBSD bug. + * doc/posix-functions/wcwidth.texi: Mention MidnightBSD as an affected + platform. + * m4/wcwidth.m4 (gl_FUNC_WCWIDTH): Update comments. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + pthread_sigmask: Document MidnightBSD bug. + * doc/posix-functions/pthread_sigmask.texi: Mention MidnightBSD as an + affected platform. + * m4/pthread_sigmask.m4 (gl_FUNC_PTHREAD_SIGMASK): Update + cross-compilation guess accordingly. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + immutable: Avoid test failures on MidnightBSD. + * tests/test-immutable.c (install_segv_handler): On FreeBSD, install the + handler also for SIGBUS. + +2021-02-07 Bruno Haible <bruno@clisp.org> + + c32is*: Avoid test failures on MidnightBSD. + * tests/test-c32isalnum.c (main): On FreeBSD, disable tests that fail on + MidnightBSD 1.1. + * tests/test-c32isalpha.c (main): Likewise. + * tests/test-c32isblank.c (main): Likewise. + * tests/test-c32islower.c (main): Likewise. + * tests/test-c32isupper.c (main): Likewise. + +2021-02-05 Paul Eggert <eggert@cs.ucla.edu> + + regex: fix comment location + * lib/regexec.c (update_regs): Move comment. + + regex-tests: add bug 11053 test + * tests/test-regex.c (main): New test case for glibc bug 11053. + + regex: debug check for set member duplicates + * lib/regex_internal.c (re_node_set_insert): Add a DEBUG_ASSERT + that would have caught some recently-fixed performance bugs + that caused sets to contain duplicate members. + + regex: fix longstanding backref match bug + This fixes a longstanding glibc bug concerning backreferences + <https://sourceware.org/11053> (2009-12-04). + * lib/regexec.c (proceed_next_node, push_fail_stack) + (pop_fail_stack): Push and pop the previous registers + as well as the current ones. All callers changed. + (set_regs): Also pop if CUR_NODE has already been checked, + so that it does not get added as a duplicate set entry. + (update_regs): Fix comment location. + * tests/test-regex.c (tests): New constant. + (bug_regex11): New test function. + (main): Bump alarm value. Call new test function. + + regex: avoid duplicate in espilon closure + * lib/regcomp.c (calc_eclosure_iter): Insert NODE into epsilon + closure first rather than last. Otherwise, the epsilon closure + might contain a duplicate of NODE. + + regex-tests: fix typo + * tests/test-regex.c (main): Fix typo that would have caused an + old test case to report incorrect values on failure. + + regex: make it easier to merge into glibc + * lib/regex_internal.h [_LIBC]: Do not include Gnulib’s dynarray.h. + + regex: minor refactoring + * lib/regexec.c (proceed_next_node): Use more-local decls. + + regex: avoid undefined behavior + * lib/regexec.c (pop_fail_stack): If the stack is empty, return -1 + instead of indulging in undefined behavior. This simplifies + callers, and avoids undefined behavior in some cases (see glibc + bug 11053, though this change does not fix that overall bug). + + regex: improve comments + * lib/regexec.c: Add and correct comments about return values. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + relocatable-prog-wrapper: Tweak today's patch. + * build-aux/install-reloc (func_create_wrapper): Clean up free.o. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + fmaf: Document QEMU bug. + * doc/posix-functions/fmaf.texi: Add note about QEMU bug. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + remainderl: Work around musl libc bug. + * doc/posix-functions/remainderl.texi: Document musl libc bug. + * m4/remainderl.m4 (gl_FUNC_REMAINDERL_WORKS): Add more tests. Update + cross compilation guess. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + log2l: Work around musl libc bugs. + * doc/posix-functions/log2l.texi: Document musl libc bugs. + * m4/log2l.m4 (gl_FUNC_LOG2L_WORKS): Add more tests. Update cross + compilation guess. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + log1pl: Work around musl libc bug. + * doc/posix-functions/log1pl.texi: Document musl libc bug. + * m4/log1pl.m4 (gl_FUNC_LOG1PL_WORKS): New macro. + (gl_FUNC_LOG1PL): Invoke it. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + log10l: Document musl libc bug. + * doc/posix-functions/log10l.texi: Document musl libc bug. + * m4/log10l.m4 (gl_FUNC_LOG10L_WORKS): Update comment and cross + compilation guess. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + logl: Document musl libc bug. + * doc/posix-functions/logl.texi: Document musl libc bug. + * m4/logl.m4 (gl_FUNC_LOGL_WORKS): Update comment and cross + compilation guess. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + expm1l: Document musl libc bug. + * doc/posix-functions/expm1l.texi: Document musl libc bug. + * m4/expm1l.m4 (gl_FUNC_EXPM1L): Update comment and cross + compilation guess. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + expl: Document musl libc bug. + * doc/posix-functions/expl.texi: Document musl libc bug. + * m4/expl.m4 (gl_FUNC_EXPL): Update comment and cross + compilation guess. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + relocatable-prog-wrapper: Update after recent changes. + * lib/relocwrapper.c: Update comments. + * modules/relocatable-prog-wrapper (Files): Add lib/scratch_buffer.h, + lib/malloc/scratch_buffer*, lib/malloc.c, lib/realloc.c, lib/free.c, + lib/mempcpy.c, lib/rawmemchr.c, m4/lstat.m4. Remove lib/lstat.c. + (Depends-on): Add c99, eloop-threshold, fcntl-h, idx, intprops, + libc-config, stddef, sys_stat. Remove alloca-opt. + (configure.ac): Invoke gl_FUNC_MALLOC_POSIX, gl_FUNC_REALLOC_POSIX, + gl_FUNC_FREE, gl_FUNC_MEMPCPY, gl_FUNC_RAWMEMCHR. + * lib/canonicalize-lgpl.c (memmove): Undefine in the relocwrapper. + * build-aux/install-reloc (func_create_wrapper): Compile also + malloc/scratch_buffer_*.c, malloc.c, realloc.c, free.c, mempcpy.c, + rawmemchr.c. Don't compile lstat.c. + + Make it possible to compile rawmemchr.c separately, unconditionally. + * lib/rawmemchr.c: Don't define rawmemchr if not needed. + + Make it possible to compile mempcpy.c separately, unconditionally. + * lib/mempcpy.c: Don't define mempcpy if not needed. + + Make it possible to compile free.c separately, unconditionally. + * m4/free.m4 (gl_FUNC_FREE): Define HAVE_FREE_POSIX. + * lib/free.c: Don't define rpl_free if not needed. + + Make it possible to compile realloc.c separately, unconditionally. + * modules/realloc-posix (configure.ac): Invoke gl_MODULE_INDICATOR. + * lib/realloc.c: Don't define rpl_realloc if not needed. + + Make it possible to compile malloc.c separately, unconditionally. + * modules/malloc-posix (configure.ac): Invoke gl_MODULE_INDICATOR. + * lib/malloc.c: Don't define rpl_malloc if not needed. + +2021-01-31 Bruno Haible <bruno@clisp.org> + + canonicalize-lgpl: Simplify. + * lib/canonicalize-lgpl.c (_GL_USE_STDLIB_ALLOC): Remove macro. + +2021-01-30 Bruno Haible <bruno@clisp.org> + + canonicalize, canonicalize-lgpl: Straighten dependencies. + * modules/canonicalize-lgpl (Depends-on): Remove free-posix, + malloc-posix. Add unistd. + * modules/canonicalize (Depends-on): Remove free-posix, xalloc. + Add unistd. + +2021-01-30 Bruno Haible <bruno@clisp.org> + + scratch_buffer: Fix dependencies. + * modules/scratch_buffer (Depends-on): Add malloc-posix, realloc-posix, + free-posix. + +2021-01-26 Bruno Haible <bruno@clisp.org> + + doc: More precise wording. + Reported by Reuben Thomas <rrt@sc3d.org> in + <https://lists.gnu.org/archive/html/bug-gnulib/2021-01/msg00300.html>. + * doc/relocatable.texi (Enabling Relocatability): Talk about package + management systems in general. + + doc: Remove obsolete text. + Suggested by Reuben Thomas <rrt@sc3d.org> in + <https://lists.gnu.org/archive/html/bug-gnulib/2021-01/msg00299.html>. + * doc/relocatable.texi (Enabling Relocatability): Stop mentioning an + issue of libtool 1.5.x. + +2021-01-26 Simon Josefsson <simon@josefsson.org> + + maintainer-makefile: Mimic bootstrap's gnulib-srcdir guessing. + * top/maint.mk (gnulib_dir): If $(srcdir)/gnulib doesn't exist, + fall back to $GNULIB_SRCDIR. + +2021-01-25 Bruno Haible <bruno@clisp.org> + + posix_spawn_file_actions_* tests: Fix module dependencies. + * modules/posix_spawn_file_actions_addclose-tests (Depends-on): Add + posix_spawn_file_actions_destroy. + * modules/posix_spawn_file_actions_addopen-tests (Depends-on): Likewise. + * modules/posix_spawn_file_actions_adddup2-tests (Depends-on): Likewise. + * modules/posix_spawn_file_actions_addchdir-tests (Depends-on): + Likewise. + * modules/posix_spawn_file_actions_addfchdir-tests (Depends-on): + Likewise. + +2021-01-25 Bruno Haible <bruno@clisp.org> + + posix_spawn_file_actions_addclose: Relax configure test. + * m4/posix_spawn.m4 (gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE): Test a + negative file descriptor, not an out-of-range file descriptor. + * tests/test-posix_spawn_file_actions_addclose.c (main): Add comment. + * doc/posix-functions/posix_spawn_file_actions_addclose.texi: Update. + +2021-01-25 Simon Josefsson <simon@josefsson.org> + + getaddrinfo: Doc fix. + * doc/posix-functions/getaddrinfo.texi (getaddrinfo): Gnulib does + not support IDN. + +2021-01-24 Bruno Haible <bruno@clisp.org> + + getcwd: Fix cross-compilation guess for musl libc. + * m4/getcwd-abort-bug.m4 (gl_FUNC_GETCWD_ABORT_BUG): Guess no also on + musl libc. + * doc/posix-functions/getcwd.texi: Update platform info. + +2021-01-24 Bruno Haible <bruno@clisp.org> + + expm1l: Fix configure test result with GCC 10 on powerpc64le. + * m4/expm1l.m4 (gl_FUNC_EXPM1L): Change test to avoid GCC optimization. + +2021-01-23 Bruno Haible <bruno@clisp.org> + + utime: Fix configure test (regression 2020-12-04). + Reported by Ryan Schmidt <wget@ryandesign.com> via Tim Rühsen in + <https://lists.gnu.org/archive/html/bug-gnulib/2021-01/msg00282.html>. + * m4/utime.m4 (gl_FUNC_UTIME): In the test program, include <utime.h>, + not <time.h>. + 2021-01-23 Paul Eggert <eggert@cs.ucla.edu> libc-config: port to Xcode 7 diff --git a/DEPENDENCIES b/DEPENDENCIES index e7b9593..fe70558 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -9,7 +9,7 @@ at any time. * A C runtime, compiler, linker, etc. + Mandatory. Using the platform's native 'cc' gives good portability - exposure, but you can also use GCC 2.95 or newer. + exposure, but you can also use GCC 3.1 or newer. + GCC Homepage: https://gcc.gnu.org/ + Download: @@ -25,7 +25,10 @@ at any time. https://ftp.gnu.org/gnu/make/ * GNU M4 1.4.5 or newer. - + 1.4.5 or newer is mandatory, but 1.4.9 or newer is recommended. + + Mandatory. + 1.4.5 or newer is mandatory, but 1.4.9 or newer is recommended. + If you want to build it from source, use the tarball from + https://gitlab.com/gnu-m4/ci-distcheck/-/jobs/artifacts/master/raw/m4-snapshot.tar?job=check-optimized + Homepage: https://www.gnu.org/software/m4/ + Download: @@ -90,6 +93,15 @@ at any time. + Download: https://ftp.gnu.org/gnu/grep/ +* Awk. + + Mandatory. + Using the platform's native awk, mawk, or nawk gives good portability + exposure, but you can also use GNU awk. + + Homepage: + https://www.gnu.org/software/gawk/ + + Download: + https://ftp.gnu.org/gnu/gawk/ + * GNU gettext. + If your project wants to follow GNU Coding Standards: + Always use the newest available gettext release, see @@ -104,6 +116,10 @@ at any time. https://www.gnu.org/software/gettext/ + Download: https://ftp.gnu.org/gnu/gettext/ + + Pre-built package name: + - On Debian and Debian-based systems: gettext, + - On Red Hat distributions: gettext. + - Other: https://repology.org/project/gettext/versions * Bison 2.0 or newer. + Recommended. @@ -112,6 +128,10 @@ at any time. https://www.gnu.org/software/bison/ + Download: https://ftp.gnu.org/gnu/bison/ + + Pre-built package name: + - On Debian and Debian-based systems: bison, + - On Red Hat distributions: bison. + - Other: https://repology.org/project/bison/versions * GNU gperf 3.0.1 or newer. + 3.0.1 or newer is mandatory, but 3.1 or newer is recommended. @@ -120,6 +140,10 @@ at any time. https://www.gnu.org/software/gperf/ + Download: https://ftp.gnu.org/gnu/gperf/ + + Pre-built package name: + - On Debian and Debian-based systems: gperf, + - On Red Hat distributions: gperf. + - Other: https://repology.org/project/gperf/versions * Texinfo 4.6 or newer. + Recommended. @@ -128,6 +152,10 @@ at any time. https://www.gnu.org/software/texinfo/ + Download: https://ftp.gnu.org/gnu/texinfo/ + + Pre-built package name: + - On Debian and Debian-based systems: texinfo, + - On Red Hat distributions: texinfo. + - Other: https://repology.org/project/texinfo/versions * GNU sed. + Recommended. @@ -60,6 +60,11 @@ User visible incompatible changes Date Modules Changes +2021-02-28 parse-datetime The parse_datetime2 function has been moved + to the new parse-datetime2 module, so that + programs that need just parse_datetime need + not build the fancier function. + 2020-12-23 execute These functions no longer execute scripts without spawn-pipe '#!' marker through /bin/sh. To execute such a posix_spawn script as a shell script, either add a '#!/bin/sh' diff --git a/build-aux/config.guess b/build-aux/config.guess index f772702..1972fda 100755 --- a/build-aux/config.guess +++ b/build-aux/config.guess @@ -2,7 +2,7 @@ # Attempt to guess a canonical system name. # Copyright 1992-2021 Free Software Foundation, Inc. -timestamp='2021-01-01' +timestamp='2021-01-25' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -188,10 +188,9 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ - "/sbin/$sysctl" 2>/dev/null || \ - "/usr/sbin/$sysctl" 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)) case "$UNAME_MACHINE_ARCH" in aarch64eb) machine=aarch64_be-unknown ;; @@ -1483,8 +1482,8 @@ EOF i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; - i*86:AROS:*:*) - echo "$UNAME_MACHINE"-pc-aros + *:AROS:*:*) + echo "$UNAME_MACHINE"-unknown-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx diff --git a/build-aux/config.libpath b/build-aux/config.libpath index 6d0e550..0823857 100755 --- a/build-aux/config.libpath +++ b/build-aux/config.libpath @@ -66,7 +66,7 @@ case $host_os in dgux*) shlibpath_var=LD_LIBRARY_PATH ;; - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) shlibpath_var=LD_LIBRARY_PATH ;; gnu*) diff --git a/build-aux/config.rpath b/build-aux/config.rpath index 69988c5..4b7dc49 100755 --- a/build-aux/config.rpath +++ b/build-aux/config.rpath @@ -371,7 +371,7 @@ else hardcode_direct=yes hardcode_minus_L=yes ;; - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; @@ -547,7 +547,7 @@ case "$host_os" in freebsd[23].*) library_names_spec='$libname$shrext$versuffix' ;; - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) library_names_spec='$libname$shrext' ;; gnu*) diff --git a/build-aux/config.sub b/build-aux/config.sub index b0f8492..63c1f1c 100755 --- a/build-aux/config.sub +++ b/build-aux/config.sub @@ -2,7 +2,7 @@ # Configuration validation subroutine script. # Copyright 1992-2021 Free Software Foundation, Inc. -timestamp='2021-01-07' +timestamp='2021-01-08' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -1683,12 +1683,15 @@ fi # Now, validate our (potentially fixed-up) OS. case $os in - # Sometimes we do "kernel-abi", so those need to count as OSes. + # Sometimes we do "kernel-libc", so those need to count as OSes. musl* | newlib* | uclibc*) ;; - # Likewise for "kernel-libc" + # Likewise for "kernel-abi" eabi* | gnueabi*) ;; + # VxWorks passes extra cpu info in the 4th filed. + simlinux | simwindows | spe) + ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. @@ -1751,6 +1754,8 @@ case $kernel-$os in ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; nto-qnx*) ;; os2-emx) diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog index de76f65..9ff15f6 100755 --- a/build-aux/gitlog-to-changelog +++ b/build-aux/gitlog-to-changelog @@ -35,7 +35,7 @@ eval 'exec perl -wSx "$0" "$@"' if 0; -my $VERSION = '2020-04-04 15:07'; # UTC +my $VERSION = '2021-02-24 23:42'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook @@ -455,7 +455,8 @@ sub git_dir_option($) # If there were any lines if (@line == 0) { - warn "$ME: warning: empty commit message:\n $date_line\n"; + warn "$ME: warning: empty commit message:\n" + . " commit $sha\n $date_line\n"; } else { diff --git a/build-aux/install-reloc b/build-aux/install-reloc index bb43e5d..f77b0d1 100755 --- a/build-aux/install-reloc +++ b/build-aux/install-reloc @@ -237,8 +237,16 @@ func_create_wrapper () "$srcdir"/readlink.c \ "$srcdir"/stat.c \ "$srcdir"/canonicalize-lgpl.c \ + "$srcdir"/malloc/scratch_buffer_dupfree.c \ + "$srcdir"/malloc/scratch_buffer_grow.c \ + "$srcdir"/malloc/scratch_buffer_grow_preserve.c \ + "$srcdir"/malloc/scratch_buffer_set_array_size.c \ + "$srcdir"/malloc.c \ + "$srcdir"/realloc.c \ + "$srcdir"/free.c \ + "$srcdir"/mempcpy.c \ + "$srcdir"/rawmemchr.c \ "$srcdir"/malloca.c \ - "$srcdir"/lstat.c \ "$srcdir"/relocatable.c \ "$srcdir"/setenv.c \ "$srcdir"/c-ctype.c \ @@ -255,8 +263,16 @@ func_create_wrapper () readlink.o \ stat.o \ canonicalize-lgpl.o \ + scratch_buffer_dupfree.o \ + scratch_buffer_grow.o \ + scratch_buffer_grow_preserve.o \ + scratch_buffer_set_array_size.o \ + malloc.o \ + realloc.o \ + free.o \ + mempcpy.o \ + rawmemchr.o \ malloca.o \ - lstat.o \ relocatable.o \ setenv.o \ c-ctype.o diff --git a/build-aux/reloc-ldflags b/build-aux/reloc-ldflags index fff3d79..ff748fe 100755 --- a/build-aux/reloc-ldflags +++ b/build-aux/reloc-ldflags @@ -56,7 +56,7 @@ esac origin_token= case "$host_os" in linux* | gnu* | kfreebsd* | \ - freebsd* | dragonfly* | \ + freebsd* | dragonfly* | midnightbsd* | \ netbsd* | \ openbsd* | \ solaris* | \ diff --git a/build-aux/texinfo.tex b/build-aux/texinfo.tex index dac7ae3..2bab634 100644 --- a/build-aux/texinfo.tex +++ b/build-aux/texinfo.tex @@ -3,9 +3,9 @@ % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % -\def\texinfoversion{2020-11-25.18} +\def\texinfoversion{2021-02-20.11} % -% Copyright 1985, 1986, 1988, 1990-2020 Free Software Foundation, Inc. +% Copyright 1985, 1986, 1988, 1990-2021 Free Software Foundation, Inc. % % This texinfo.tex file is free software: you can redistribute it and/or % modify it under the terms of the GNU General Public License as @@ -8931,7 +8931,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \else \ifhavexrefs % We (should) know the real title if we have the xref values. - \def\printedrefname{\refx{#1-title}{}}% + \def\printedrefname{\refx{#1-title}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% @@ -9025,7 +9025,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd\printedrefnamebox = 0pt - \refx{#1-snt}{}% + \refx{#1-snt}% \else \printedrefname \fi @@ -9060,9 +9060,9 @@ might help (with 'rm \jobname.?? \jobname.??s')% \else % Reference within this manual. % - % Only output a following space if the -snt ref is nonempty; for - % @unnumbered and @anchor, it won't be. - \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + % Only output a following space if the -snt ref is nonempty, as the ref + % will be empty for @unnumbered and @anchor. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi % % output the `[mynode]' via the macro below so it can be overridden. @@ -9073,7 +9073,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% ,\space % % output the `page 3'. - \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \turnoffactive \putwordpage\tie\refx{#1-pg}% % Add a , if xref followed by a space \if\space\noexpand\tokenafterxref ,% \else\ifx\ \tokenafterxref ,% @TAB @@ -9150,9 +9150,8 @@ might help (with 'rm \jobname.?? \jobname.??s')% \fi\fi\fi } -% \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME. SUFFIX -% is output afterwards if non-empty. -\def\refx#1#2{% +% \refx{NAME} - reference a cross-reference string named NAME. +\def\refx#1{% \requireauxfile {% \indexnofonts @@ -9179,7 +9178,6 @@ might help (with 'rm \jobname.?? \jobname.??s')% % It's defined, so just use it. \thisrefX \fi - #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Define a control @@ -9289,10 +9287,10 @@ might help (with 'rm \jobname.?? \jobname.??s')% \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other - \catcode`\_=\other - \catcode`\|=\other - \catcode`\<=\other - \catcode`\>=\other + \catcode`\_=\active + \catcode`\|=\active + \catcode`\<=\active + \catcode`\>=\active \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other diff --git a/config/srclist.txt b/config/srclist.txt index d669fd8..a55c95f 100644 --- a/config/srclist.txt +++ b/config/srclist.txt @@ -55,7 +55,7 @@ $LIBCSRC include/idx.h lib #$LIBCSRC malloc/dynarray.h lib/malloc #$LIBCSRC malloc/dynarray_at_failure.c lib/malloc #$LIBCSRC malloc/dynarray_emplace_enlarge.c lib/malloc -$LIBCSRC malloc/dynarray_finalize.c lib/malloc +#$LIBCSRC malloc/dynarray_finalize.c lib/malloc #$LIBCSRC malloc/dynarray_resize.c lib/malloc #$LIBCSRC malloc/dynarray_resize_clear.c lib/malloc $LIBCSRC include/scratch_buffer.h lib/malloc diff --git a/doc/INSTALL b/doc/INSTALL index 8865734..e82fd21 100644 --- a/doc/INSTALL +++ b/doc/INSTALL @@ -1,8 +1,8 @@ Installation Instructions ************************* - Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software -Foundation, Inc. + Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free +Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -225,7 +225,7 @@ order to use an ANSI C compiler: and if that doesn't work, install pre-built binaries of GCC for HP-UX. - HP-UX 'make' updates targets which have the same time stamps as their + HP-UX 'make' updates targets which have the same timestamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. diff --git a/doc/INSTALL.ISO b/doc/INSTALL.ISO index 8865734..e82fd21 100644 --- a/doc/INSTALL.ISO +++ b/doc/INSTALL.ISO @@ -1,8 +1,8 @@ Installation Instructions ************************* - Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software -Foundation, Inc. + Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free +Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -225,7 +225,7 @@ order to use an ANSI C compiler: and if that doesn't work, install pre-built binaries of GCC for HP-UX. - HP-UX 'make' updates targets which have the same time stamps as their + HP-UX 'make' updates targets which have the same timestamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. diff --git a/doc/INSTALL.UTF-8 b/doc/INSTALL.UTF-8 index 8865734..e82fd21 100644 --- a/doc/INSTALL.UTF-8 +++ b/doc/INSTALL.UTF-8 @@ -1,8 +1,8 @@ Installation Instructions ************************* - Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software -Foundation, Inc. + Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free +Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright @@ -225,7 +225,7 @@ order to use an ANSI C compiler: and if that doesn't work, install pre-built binaries of GCC for HP-UX. - HP-UX 'make' updates targets which have the same time stamps as their + HP-UX 'make' updates targets which have the same timestamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. diff --git a/doc/glibc-functions/sethostname.texi b/doc/glibc-functions/sethostname.texi index 8294a4a..d34f4a1 100644 --- a/doc/glibc-functions/sethostname.texi +++ b/doc/glibc-functions/sethostname.texi @@ -37,5 +37,5 @@ The first parameter is @code{char *} instead of @code{const char *} on some platforms: Solaris 11 2010-11. @item The second parameter is @code{int} instead of @code{size_t} -on some platforms: Mac OS X 10.12, Solaris 11 2010-11. +on some platforms: Mac OS X 10.12, MidnightBSD 2.0, Solaris 11 2010-11. @end itemize diff --git a/doc/install.texi b/doc/install.texi index 875b8eb..3bedb4e 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -5,8 +5,8 @@ @unnumbered Installation Instructions -Copyright @copyright{} 1994-1996, 1999-2002, 2004-2017, 2020 Free -Software Foundation, Inc. +Copyright @copyright{} 1994--1996, 1999--2002, 2004--2017, 2020--2021 +Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice diff --git a/doc/posix-functions/expl.texi b/doc/posix-functions/expl.texi index d0810b2..f70589f 100644 --- a/doc/posix-functions/expl.texi +++ b/doc/posix-functions/expl.texi @@ -23,7 +23,7 @@ MSVC 14. @item This function produces results which are accurate to only 16 digits on some platforms: -NetBSD 9.0. +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x, NetBSD 9.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/expm1l.texi b/doc/posix-functions/expm1l.texi index 4cd58a8..059d5fc 100644 --- a/doc/posix-functions/expm1l.texi +++ b/doc/posix-functions/expm1l.texi @@ -17,7 +17,7 @@ IRIX 6.5. @item This function produces results which are accurate to only 16 digits on some platforms: -Mac OS X 10.5, NetBSD 8.0. +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x, Mac OS X 10.5, NetBSD 8.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/fmaf.texi b/doc/posix-functions/fmaf.texi index 1e0d34a..3551d19 100644 --- a/doc/posix-functions/fmaf.texi +++ b/doc/posix-functions/fmaf.texi @@ -18,4 +18,8 @@ glibc 2.11, Mac OS X 10.5, FreeBSD 6.4/x86, FreeBSD 12.2/arm, Cygwin 1.5, mingw. Portability problems not fixed by Gnulib: @itemize +@item +This function produces wrong results on some platforms: +musl libc/powerpc64le when emulated by QEMU 5.0.0. +@c https://bugs.launchpad.net/qemu/+bug/1912934 @end itemize diff --git a/doc/posix-functions/getaddrinfo.texi b/doc/posix-functions/getaddrinfo.texi index eae5b8b..8c2bc7f 100644 --- a/doc/posix-functions/getaddrinfo.texi +++ b/doc/posix-functions/getaddrinfo.texi @@ -21,4 +21,7 @@ that is different from @code{cdecl}. Portability problems not fixed by Gnulib: @itemize +@item +Unlike glibc's implementation, gnulib's replacement does not support +internationalized domain names (IDN) encoding. @end itemize diff --git a/doc/posix-functions/getcwd.texi b/doc/posix-functions/getcwd.texi index 9ca0ae3..9a4cf1e 100644 --- a/doc/posix-functions/getcwd.texi +++ b/doc/posix-functions/getcwd.texi @@ -38,7 +38,7 @@ Portability problems fixed by Gnulib module @code{getcwd}: @item This function does not handle long file names (greater than @code{PATH_MAX}) correctly on some platforms: -glibc on Linux 2.4.20, Mac OS X 10.13, FreeBSD 6.4, NetBSD 9.0, OpenBSD 4.9, AIX 7.1. +glibc on Linux 2.4.20, musl libc 1.2.2/powerpc64le, Mac OS X 10.13, FreeBSD 6.4, NetBSD 9.0, OpenBSD 6.7, AIX 7.1. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/getlogin_r.texi b/doc/posix-functions/getlogin_r.texi index d17c541..c70eb32 100644 --- a/doc/posix-functions/getlogin_r.texi +++ b/doc/posix-functions/getlogin_r.texi @@ -25,7 +25,7 @@ Portability problems not fixed by Gnulib: @itemize @item This function has an incompatible declaration on some platforms: -Solaris 11.4 (when @code{_POSIX_PTHREAD_SEMANTICS} is not defined). +MidnightBSD 2.0, Solaris 11.4 (when @code{_POSIX_PTHREAD_SEMANTICS} is not defined). @item This function fails even when standard input is a tty on some platforms: HP-UX 11.11. diff --git a/doc/posix-functions/initstate.texi b/doc/posix-functions/initstate.texi index fa03e99..3346767 100644 --- a/doc/posix-functions/initstate.texi +++ b/doc/posix-functions/initstate.texi @@ -18,4 +18,11 @@ Cygwin 1.5.25. Portability problems not fixed by Gnulib: @itemize +@item +The first parameter is @code{unsigned long} instead of @code{unsigned int} on +some platforms: +MidnightBSD 2.0. +@item +The third parameter is @code{long} instead of @code{size_t} on some platforms: +MidnightBSD 2.0. @end itemize diff --git a/doc/posix-functions/log10l.texi b/doc/posix-functions/log10l.texi index 7dd6f49..ffddbcb 100644 --- a/doc/posix-functions/log10l.texi +++ b/doc/posix-functions/log10l.texi @@ -26,7 +26,7 @@ IRIX 6.5. @item This function produces results which are accurate to only 16 digits on some platforms: -NetBSD 9.0. +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x, NetBSD 9.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/log1pl.texi b/doc/posix-functions/log1pl.texi index 802c2e6..be81d60 100644 --- a/doc/posix-functions/log1pl.texi +++ b/doc/posix-functions/log1pl.texi @@ -11,6 +11,10 @@ Portability problems fixed by either Gnulib module @code{log1pl} or @code{log1pl @item This function is missing on some platforms: FreeBSD 6.0, NetBSD 9.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 9, Cygwin 1.7.x, MSVC 9, Android 4.4. +@item +This function produces results which are accurate to only 16 digits on some +platforms: +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x. @end itemize Portability problems fixed by Gnulib module @code{log1pl-ieee}: diff --git a/doc/posix-functions/log2l.texi b/doc/posix-functions/log2l.texi index 24e367c..563a67e 100644 --- a/doc/posix-functions/log2l.texi +++ b/doc/posix-functions/log2l.texi @@ -14,6 +14,13 @@ FreeBSD 6.0, NetBSD 9.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, older IRIX @item This function is not declared on some platforms: IRIX 6.5. +@item +This function produces results which are accurate to only 16 digits on some +platforms: +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x. +@item +This function returns Infinity for some large finite arguments on some platforms: +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/logl.texi b/doc/posix-functions/logl.texi index 1e7918b..e0d04b5 100644 --- a/doc/posix-functions/logl.texi +++ b/doc/posix-functions/logl.texi @@ -20,7 +20,7 @@ glibc 2.7 on Linux/SPARC64. @item This function produces results which are accurate to only 16 digits on some platforms: -NetBSD 9.0. +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x, NetBSD 9.0. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/open_memstream.texi b/doc/posix-functions/open_memstream.texi index e287664..479738e 100644 --- a/doc/posix-functions/open_memstream.texi +++ b/doc/posix-functions/open_memstream.texi @@ -16,3 +16,6 @@ Portability problems not fixed by Gnulib: This function is missing on some platforms: Mac OS X 10.5, FreeBSD 6.0, NetBSD 7.1, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.3, Cygwin 1.5.x, mingw, MSVC 14, Android 5.1. @end itemize + +An alternative to the @code{open_memstream} function is the Gnulib module +@code{string-buffer}. diff --git a/doc/posix-functions/posix_spawn_file_actions_addclose.texi b/doc/posix-functions/posix_spawn_file_actions_addclose.texi index 6a1ba1b..db5bcfd 100644 --- a/doc/posix-functions/posix_spawn_file_actions_addclose.texi +++ b/doc/posix-functions/posix_spawn_file_actions_addclose.texi @@ -12,8 +12,8 @@ Portability problems fixed by Gnulib: This function is missing on some platforms: FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 9, Cygwin 1.7.x, mingw, MSVC 14, Android 8.1. @item -This function does not reject a too large file descriptor on some platforms: -musl libc, Solaris 11.4. +This function does not reject a negative file descriptor on some platforms: +musl libc. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/pthread_sigmask.texi b/doc/posix-functions/pthread_sigmask.texi index 2814662..aefe0a9 100644 --- a/doc/posix-functions/pthread_sigmask.texi +++ b/doc/posix-functions/pthread_sigmask.texi @@ -18,7 +18,7 @@ FreeBSD 6.4, OpenBSD 3.8. @item This function does nothing and always returns 0 in programs that are not linked with @code{-lpthread} on some platforms: -FreeBSD 6.4, HP-UX 11.31, Solaris 9. +FreeBSD 6.4, MidnightBSD 1.1, HP-UX 11.31, Solaris 9. @item When it fails, this functions returns @minus{}1 instead of the error number on some platforms: diff --git a/doc/posix-functions/remainderl.texi b/doc/posix-functions/remainderl.texi index e1b439f..1a8f625 100644 --- a/doc/posix-functions/remainderl.texi +++ b/doc/posix-functions/remainderl.texi @@ -17,6 +17,10 @@ IRIX 6.5. @item This function returns completely wrong values on some platforms: OpenBSD 5.1/SPARC. +@item +This function produces results which are accurate to only 16 digits on some +platforms: +musl libc 1.2.2/arm64, musl libc 1.2.2/s390x. @end itemize Portability problems fixed by Gnulib module @code{remainderl-ieee}: diff --git a/doc/posix-functions/srandom.texi b/doc/posix-functions/srandom.texi index d553373..12df916 100644 --- a/doc/posix-functions/srandom.texi +++ b/doc/posix-functions/srandom.texi @@ -22,4 +22,8 @@ Portability problems not fixed by Gnulib: This function has a slightly incompatible declaration (the return type being @samp{long} instead of @samp{void}) on some platforms: Cygwin 1.5.25. +@item +The parameter is @code{unsigned long} instead of @code{unsigned int} on some +platforms: +MidnightBSD 2.0. @end itemize diff --git a/doc/posix-functions/wcwidth.texi b/doc/posix-functions/wcwidth.texi index 86d2397..0540bb6 100644 --- a/doc/posix-functions/wcwidth.texi +++ b/doc/posix-functions/wcwidth.texi @@ -17,7 +17,7 @@ glibc 2.8. @item This function handles combining characters in UTF-8 locales incorrectly on some platforms: -NetBSD 9.0, OpenBSD 5.8. +NetBSD 9.0, OpenBSD 5.8, MidnightBSD 1.1. @item This function returns 2 for characters with ambiguous east asian width, even in Western locales, on some platforms: diff --git a/doc/posix-headers/stddef.texi b/doc/posix-headers/stddef.texi index dbc0103..ba27fa8 100644 --- a/doc/posix-headers/stddef.texi +++ b/doc/posix-headers/stddef.texi @@ -27,6 +27,10 @@ NetBSD 5.0 Some platforms provide a @code{NULL} macro whose value does not have the size of a pointer: AIX 7.2 with xlc in 64-bit mode. + +@item +When this header file is provided by TinyCC 0.9.27 on glibc systems, it does +not fulfil the expectations of other glibc header files. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/relocatable.texi b/doc/relocatable.texi index fca0ea5..f8eec1e 100644 --- a/doc/relocatable.texi +++ b/doc/relocatable.texi @@ -8,7 +8,8 @@ and have it work correctly (including i18n). So many users need to go through @code{configure; make; make install} with all its dependencies, options, and hurdles. -Red Hat, Debian, and similar package systems solve the ``ease of +Most package management systems, that allow the user to install +pre-built binaries of the packages, solve the ``ease of installation'' problem, but they hardwire path names, usually to @file{/usr} or @file{/usr/local}. This means that users need root privileges to install a binary package, and prevents installing two @@ -52,9 +53,7 @@ make install DESTDIR=/tmp/inst$$ Installation with @option{--enable-relocatable} will not work for setuid or setgid executables, because such executables search only -system library paths for security reasons. Also, installation with -@option{--enable-relocatable} might not work on OpenBSD, when the -package contains shared libraries and libtool versions 1.5.xx are used. +system library paths for security reasons. The runtime penalty and size penalty are negligible on GNU/Linux (just one system call more when an executable is launched), and small on diff --git a/lib/argp-namefrob.h b/lib/argp-namefrob.h index f3216d7..de1a26e 100644 --- a/lib/argp-namefrob.h +++ b/lib/argp-namefrob.h @@ -95,43 +95,56 @@ #undef __vsnprintf #define __vsnprintf vsnprintf -#if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED +#if (defined HAVE_DECL_CLEARERR_UNLOCKED && !HAVE_DECL_CLEARERR_UNLOCKED \ + && !defined clearerr_unlocked) # define clearerr_unlocked(x) clearerr (x) #endif -#if defined(HAVE_DECL_FEOF_UNLOCKED) && !HAVE_DECL_FEOF_UNLOCKED +#if (defined HAVE_DECL_FEOF_UNLOCKED && !HAVE_DECL_FEOF_UNLOCKED \ + && !defined feof_unlocked) # define feof_unlocked(x) feof (x) #endif -#if defined(HAVE_DECL_FERROR_UNLOCKED) && !HAVE_DECL_FERROR_UNLOCKED +#if (defined HAVE_DECL_FERROR_UNLOCKED && !HAVE_DECL_FERROR_UNLOCKED \ + && !defined ferror_unlocked) # define ferror_unlocked(x) ferror (x) #endif -#if defined(HAVE_DECL_FFLUSH_UNLOCKED) && !HAVE_DECL_FFLUSH_UNLOCKED +#if (defined HAVE_DECL_FFLUSH_UNLOCKED && !HAVE_DECL_FFLUSH_UNLOCKED \ + && !defined fflush_unlocked) # define fflush_unlocked(x) fflush (x) #endif -#if defined(HAVE_DECL_FGETS_UNLOCKED) && !HAVE_DECL_FGETS_UNLOCKED +#if (defined HAVE_DECL_FGETS_UNLOCKED && !HAVE_DECL_FGETS_UNLOCKED \ + && !defined fgets_unlocked) # define fgets_unlocked(x,y,z) fgets (x,y,z) #endif -#if defined(HAVE_DECL_FPUTC_UNLOCKED) && !HAVE_DECL_FPUTC_UNLOCKED +#if (defined HAVE_DECL_FPUTC_UNLOCKED && !HAVE_DECL_FPUTC_UNLOCKED \ + && !defined fputc_unlocked) # define fputc_unlocked(x,y) fputc (x,y) #endif -#if defined(HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED +#if (defined HAVE_DECL_FPUTS_UNLOCKED && !HAVE_DECL_FPUTS_UNLOCKED \ + && !defined fputs_unlocked) # define fputs_unlocked(x,y) fputs (x,y) #endif -#if defined(HAVE_DECL_FREAD_UNLOCKED) && !HAVE_DECL_FREAD_UNLOCKED +#if (defined HAVE_DECL_FREAD_UNLOCKED && !HAVE_DECL_FREAD_UNLOCKED \ + && !defined fread_unlocked) # define fread_unlocked(w,x,y,z) fread (w,x,y,z) #endif -#if defined(HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED +#if (defined HAVE_DECL_FWRITE_UNLOCKED && !HAVE_DECL_FWRITE_UNLOCKED \ + && !defined fwrite_unlocked) # define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) #endif -#if defined(HAVE_DECL_GETC_UNLOCKED) && !HAVE_DECL_GETC_UNLOCKED +#if (defined HAVE_DECL_GETC_UNLOCKED && !HAVE_DECL_GETC_UNLOCKED \ + && !defined getc_unlocked) # define getc_unlocked(x) getc (x) #endif -#if defined(HAVE_DECL_GETCHAR_UNLOCKED) && !HAVE_DECL_GETCHAR_UNLOCKED -# define getchar_unlocked() getchar () +#if (defined HAVE_DECL_GETCHAR_UNLOCKED && !HAVE_DECL_GETCHAR_UNLOCKED \ + && !defined getchar_unlocked) +# define getchar_unlocked() getchar () #endif -#if defined(HAVE_DECL_PUTC_UNLOCKED) && !HAVE_DECL_PUTC_UNLOCKED +#if (defined HAVE_DECL_PUTC_UNLOCKED && !HAVE_DECL_PUTC_UNLOCKED \ + && !defined putc_unlocked) # define putc_unlocked(x,y) putc (x,y) #endif -#if defined(HAVE_DECL_PUTCHAR_UNLOCKED) && !HAVE_DECL_PUTCHAR_UNLOCKED +#if (defined HAVE_DECL_PUTCHAR_UNLOCKED && !HAVE_DECL_PUTCHAR_UNLOCKED \ + && !defined putchar_unlocked) # define putchar_unlocked(x) putchar (x) #endif diff --git a/lib/asyncsafe-spin.c b/lib/asyncsafe-spin.c index ba22b9c..d0cdb39 100644 --- a/lib/asyncsafe-spin.c +++ b/lib/asyncsafe-spin.c @@ -190,7 +190,7 @@ do_unlock (asyncsafe_spinlock_t *lock) abort (); } -# elif (defined __GNUC__ || defined __clang__ || defined __SUNPRO_C) && (defined __sparc || defined __i386 || defined __x86_64__) +# elif ((defined __GNUC__ || defined __clang__ || defined __SUNPRO_C) && (defined __sparc || defined __i386 || defined __x86_64__)) || (defined __TINYC__ && (defined __i386 || defined __x86_64__)) /* For older versions of GCC or clang, use inline assembly. GCC, clang, and the Oracle Studio C 12 compiler understand GCC's extended asm syntax, but the plain Oracle Studio C 11 compiler understands only @@ -200,9 +200,14 @@ do_unlock (asyncsafe_spinlock_t *lock) static void memory_barrier (void) { -# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 +# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 || defined __TINYC__ # if defined __i386 || defined __x86_64__ +# if defined __TINYC__ && defined __i386 + /* Cannot use the SSE instruction "mfence" with this compiler. */ + asm volatile ("lock orl $0,(%esp)"); +# else asm volatile ("mfence"); +# endif # endif # if defined __sparc asm volatile ("membar 2"); @@ -223,7 +228,7 @@ static unsigned int atomic_compare_and_swap (volatile unsigned int *vp, unsigned int cmp, unsigned int newval) { -# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 +# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 || defined __TINYC__ unsigned int oldval; # if defined __i386 || defined __x86_64__ asm volatile (" lock\n cmpxchgl %3,(%1)" diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c index bf63355..c6fef17 100644 --- a/lib/canonicalize-lgpl.c +++ b/lib/canonicalize-lgpl.c @@ -21,7 +21,6 @@ optimizes away the name == NULL test below. */ # define _GL_ARG_NONNULL(params) -# define _GL_USE_STDLIB_ALLOC 1 # include <libc-config.h> #endif @@ -76,6 +75,12 @@ # define __rawmemchr rawmemchr # define __readlink readlink # define __stat stat +# if IN_RELOCWRAPPER + /* When building the relocatable program wrapper, use the system's memmove + function, not the gnulib override, otherwise we would get a link error. + */ +# undef memmove +# endif #endif /* Suppress bogus GCC -Wmaybe-uninitialized warnings. */ diff --git a/lib/dynarray.h b/lib/dynarray.h index 6da3e87..37053d0 100644 --- a/lib/dynarray.h +++ b/lib/dynarray.h @@ -19,8 +19,6 @@ #ifndef _GL_DYNARRAY_H #define _GL_DYNARRAY_H -#include <libc-config.h> - #define __libc_dynarray_at_failure gl_dynarray_at_failure #define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge #define __libc_dynarray_finalize gl_dynarray_finalize @@ -19,15 +19,19 @@ #include <config.h> +/* Specification. */ #include <stdlib.h> -#include <errno.h> +/* A function definition is only needed if HAVE_FREE_POSIX is not defined. */ +#if !HAVE_FREE_POSIX + +# include <errno.h> void rpl_free (void *p) -#undef free +# undef free { -#if defined __GNUC__ && !defined __clang__ +# if defined __GNUC__ && !defined __clang__ /* An invalid GCC optimization <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98396> would optimize away the assignments in the code below, when link-time @@ -39,9 +43,11 @@ rpl_free (void *p) errno = 0; free (p); errno = err[errno == 0]; -#else +# else int err = errno; free (p); errno = err; -#endif +# endif } + +#endif @@ -21,7 +21,7 @@ optimizes away the pattern == NULL test below. */ # define _GL_ARG_NONNULL(params) -# include <config.h> +# include <libc-config.h> #endif diff --git a/lib/glob.in.h b/lib/glob.in.h index d4270d7..d8b03c5 100644 --- a/lib/glob.in.h +++ b/lib/glob.in.h @@ -70,7 +70,9 @@ typedef int (*_gl_glob_errfunc_fn) (const char *, int); /* Preparations for including the standard GNU C Library header. */ -# include <libc-config.h> +# ifndef __attribute_maybe_unused__ +# include <libc-config.h> +# endif # include <stddef.h> diff --git a/lib/malloc.c b/lib/malloc.c index 325064d..887cdde 100644 --- a/lib/malloc.c +++ b/lib/malloc.c @@ -30,7 +30,11 @@ #include <stdlib.h> -#include <errno.h> +/* A function definition is only needed if NEED_MALLOC_GNU is defined above + or if the module 'malloc-posix' requests it. */ +#if NEED_MALLOC_GNU || (GNULIB_MALLOC_POSIX && !HAVE_MALLOC_POSIX) + +# include <errno.h> /* Allocate an N-byte block of memory from the heap. If N is zero, allocate a 1-byte block. */ @@ -40,17 +44,19 @@ rpl_malloc (size_t n) { void *result; -#if NEED_MALLOC_GNU +# if NEED_MALLOC_GNU if (n == 0) n = 1; -#endif +# endif result = malloc (n); -#if !HAVE_MALLOC_POSIX +# if !HAVE_MALLOC_POSIX if (result == NULL) errno = ENOMEM; -#endif +# endif return result; } + +#endif diff --git a/lib/malloc/dynarray_at_failure.c b/lib/malloc/dynarray_at_failure.c index 0fa12c7..4f840db 100644 --- a/lib/malloc/dynarray_at_failure.c +++ b/lib/malloc/dynarray_at_failure.c @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#ifndef _LIBC +# include <libc-config.h> +#endif + #include <dynarray.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/malloc/dynarray_emplace_enlarge.c b/lib/malloc/dynarray_emplace_enlarge.c index ddfe306..0f8baf9 100644 --- a/lib/malloc/dynarray_emplace_enlarge.c +++ b/lib/malloc/dynarray_emplace_enlarge.c @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#ifndef _LIBC +# include <libc-config.h> +#endif + #include <dynarray.h> #include <errno.h> #include <intprops.h> diff --git a/lib/malloc/dynarray_finalize.c b/lib/malloc/dynarray_finalize.c index 8ec6ad2..c33da41 100644 --- a/lib/malloc/dynarray_finalize.c +++ b/lib/malloc/dynarray_finalize.c @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#ifndef _LIBC +# include <libc-config.h> +#endif + #include <dynarray.h> #include <stdlib.h> #include <string.h> diff --git a/lib/malloc/dynarray_resize.c b/lib/malloc/dynarray_resize.c index 5c60927..5a57166 100644 --- a/lib/malloc/dynarray_resize.c +++ b/lib/malloc/dynarray_resize.c @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#ifndef _LIBC +# include <libc-config.h> +#endif + #include <dynarray.h> #include <errno.h> #include <intprops.h> diff --git a/lib/malloc/dynarray_resize_clear.c b/lib/malloc/dynarray_resize_clear.c index e893d1d..9c43b00 100644 --- a/lib/malloc/dynarray_resize_clear.c +++ b/lib/malloc/dynarray_resize_clear.c @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#ifndef _LIBC +# include <libc-config.h> +#endif + #include <dynarray.h> #include <string.h> diff --git a/lib/mbtowc-lock.h b/lib/mbtowc-lock.h index 696b12c..b7c5ba8 100644 --- a/lib/mbtowc-lock.h +++ b/lib/mbtowc-lock.h @@ -32,7 +32,15 @@ mbtowc_unlocked (wchar_t *pwc, const char *p, size_t m) /* Prohibit renaming this symbol. */ #undef gl_get_mbtowc_lock -#if defined _WIN32 && !defined __CYGWIN__ +#ifdef USE_UNLOCKED_IO + +static int +mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) +{ + return mbtowc_unlocked (pwc, p, m); +} + +#elif defined _WIN32 && !defined __CYGWIN__ extern __declspec(dllimport) CRITICAL_SECTION *gl_get_mbtowc_lock (void); diff --git a/lib/mempcpy.c b/lib/mempcpy.c index c61132e..6e9500c 100644 --- a/lib/mempcpy.c +++ b/lib/mempcpy.c @@ -19,6 +19,9 @@ /* Specification. */ #include <string.h> +/* A function definition is only needed if HAVE_MEMPCPY is not defined. */ +#if !HAVE_MEMPCPY + /* Copy N bytes of SRC to DEST, return pointer to bytes after the last written byte. */ void * @@ -26,3 +29,5 @@ mempcpy (void *dest, const void *src, size_t n) { return (char *) memcpy (dest, src, n) + n; } + +#endif diff --git a/lib/parse-datetime.y b/lib/parse-datetime.y index b8a832f..552fe5c 100644 --- a/lib/parse-datetime.y +++ b/lib/parse-datetime.y @@ -221,8 +221,10 @@ typedef struct idx_t zones_seen; bool year_seen; +#ifdef GNULIB_PARSE_DATETIME2 /* Print debugging output to stderr. */ bool parse_datetime_debug; +#endif /* Which of the 'seen' parts have been printed when debugging. */ bool debug_dates_seen; @@ -239,6 +241,16 @@ typedef struct table local_time_zone_table[3]; } parser_control; +static bool +debugging (parser_control const *pc) +{ +#ifdef GNULIB_PARSE_DATETIME2 + return pc->parse_datetime_debug; +#else + return false; +#endif +} + union YYSTYPE; static int yylex (union YYSTYPE *, parser_control *); static int yyerror (parser_control const *, char const *); @@ -421,7 +433,7 @@ debug_print_current_time (char const *item, parser_control *pc) { bool space = false; - if (!pc->parse_datetime_debug) + if (!debugging (pc)) return; /* no newline, more items printed below */ @@ -521,7 +533,7 @@ debug_print_relative_time (char const *item, parser_control const *pc) { bool space = false; - if (!pc->parse_datetime_debug) + if (!debugging (pc)) return; /* no newline, more items printed below */ @@ -802,7 +814,7 @@ date: you want portability, use the ISO 8601 format. */ if (4 <= $1.digits) { - if (pc->parse_datetime_debug) + if (debugging (pc)) { intmax_t digits = $1.digits; dbg_printf (_("warning: value %"PRIdMAX" has %"PRIdMAX" digits. " @@ -816,7 +828,7 @@ date: } else { - if (pc->parse_datetime_debug) + if (debugging (pc)) dbg_printf (_("warning: value %"PRIdMAX" has less than 4 digits. " "Assuming MM/DD/YY[YY]\n"), $1.value); @@ -1504,7 +1516,7 @@ yylex (union YYSTYPE *lvalp, parser_control *pc) tp = lookup_word (pc, buff); if (! tp) { - if (pc->parse_datetime_debug) + if (debugging (pc)) dbg_printf (_("error: unknown word '%s'\n"), buff); return '?'; } @@ -1651,7 +1663,7 @@ debug_mktime_not_ok (struct tm const *tm0, struct tm const *tm1, const bool dst_shift = eq_sec && eq_min && !eq_hour && eq_mday && eq_month && eq_year; - if (!pc->parse_datetime_debug) + if (!debugging (pc)) return; dbg_printf (_("error: invalid date/time value:\n")); @@ -1690,29 +1702,15 @@ debug_mktime_not_ok (struct tm const *tm0, struct tm const *tm1, : _("missing timezone"))); } -/* The original interface: run with debug=false and the default timezone. */ -bool -parse_datetime (struct timespec *result, char const *p, - struct timespec const *now) -{ - char const *tzstring = getenv ("TZ"); - timezone_t tz = tzalloc (tzstring); - if (!tz) - return false; - bool ok = parse_datetime2 (result, p, now, 0, tz, tzstring); - tzfree (tz); - return ok; -} - /* Parse a date/time string, storing the resulting time value into *RESULT. The string itself is pointed to by P. Return true if successful. P can be an incomplete or relative time specification; if so, use *NOW as the basis for the returned time. Default to timezone TZDEFAULT, which corresponds to tzalloc (TZSTRING). */ -bool -parse_datetime2 (struct timespec *result, char const *p, - struct timespec const *now, unsigned int flags, - timezone_t tzdefault, char const *tzstring) +static bool +parse_datetime_body (struct timespec *result, char const *p, + struct timespec const *now, unsigned int flags, + timezone_t tzdefault, char const *tzstring) { struct tm tm; struct tm tm0; @@ -1803,10 +1801,12 @@ parse_datetime2 (struct timespec *result, char const *p, parser_control pc; pc.input = p; +#ifdef GNULIB_PARSE_DATETIME2 pc.parse_datetime_debug = (flags & PARSE_DATETIME_DEBUG) != 0; +#endif if (INT_ADD_WRAPV (tmp.tm_year, TM_YEAR_BASE, &pc.year.value)) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: initial year out of range\n")); goto fail; } @@ -1900,7 +1900,7 @@ parse_datetime2 (struct timespec *result, char const *p, if (yyparse (&pc) != 0) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf ((input_sentinel <= pc.input ? _("error: parsing failed\n") : _("error: parsing failed, stopped at '%s'\n")), @@ -1911,7 +1911,7 @@ parse_datetime2 (struct timespec *result, char const *p, /* Determine effective timezone source. */ - if (pc.parse_datetime_debug) + if (debugging (&pc)) { dbg_printf (_("input timezone: ")); @@ -1953,7 +1953,7 @@ parse_datetime2 (struct timespec *result, char const *p, if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen | (pc.local_zones_seen + pc.zones_seen))) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) { if (pc.times_seen > 1) dbg_printf ("error: seen multiple time parts\n"); @@ -1969,11 +1969,11 @@ parse_datetime2 (struct timespec *result, char const *p, goto fail; } - if (! to_tm_year (pc.year, pc.parse_datetime_debug, &tm.tm_year) + if (! to_tm_year (pc.year, debugging (&pc), &tm.tm_year) || INT_ADD_WRAPV (pc.month, -1, &tm.tm_mon) || INT_ADD_WRAPV (pc.day, 0, &tm.tm_mday)) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: year, month, or day overflow\n")); goto fail; } @@ -1984,14 +1984,14 @@ parse_datetime2 (struct timespec *result, char const *p, { char const *mrd = (pc.meridian == MERam ? "am" : pc.meridian == MERpm ?"pm" : ""); - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: invalid hour %"PRIdMAX"%s\n"), pc.hour, mrd); goto fail; } tm.tm_min = pc.minutes; tm.tm_sec = pc.seconds.tv_sec; - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf ((pc.times_seen ? _("using specified time as starting value: '%s'\n") : _("using current time as starting value: '%s'\n")), @@ -2001,7 +2001,7 @@ parse_datetime2 (struct timespec *result, char const *p, { tm.tm_hour = tm.tm_min = tm.tm_sec = 0; pc.seconds.tv_nsec = 0; - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf ("warning: using midnight as starting time: 00:00:00\n"); } @@ -2047,7 +2047,7 @@ parse_datetime2 (struct timespec *result, char const *p, timezone_t tz2 = tzalloc (tz2buf); if (!tz2) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: tzalloc (\"%s\") failed\n"), tz2buf); goto fail; } @@ -2092,7 +2092,7 @@ parse_datetime2 (struct timespec *result, char const *p, if (Start == (time_t) -1) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: day '%s' " "(day ordinal=%"PRIdMAX" number=%d) " "resulted in an invalid date: '%s'\n"), @@ -2103,14 +2103,14 @@ parse_datetime2 (struct timespec *result, char const *p, goto fail; } - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("new start date: '%s' is '%s'\n"), str_days (&pc, dbg_ord, sizeof dbg_ord), debug_strfdatetime (&tm, &pc, dbg_tm, sizeof dbg_tm)); } - if (pc.parse_datetime_debug) + if (debugging (&pc)) { if (!pc.dates_seen && !pc.days_seen) dbg_printf (_("using current date as starting value: '%s'\n"), @@ -2128,7 +2128,7 @@ parse_datetime2 (struct timespec *result, char const *p, /* Add relative date. */ if (pc.rel.year | pc.rel.month | pc.rel.day) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) { if ((pc.rel.year != 0 || pc.rel.month != 0) && tm.tm_mday != 15) dbg_printf (_("warning: when adding relative months/years, " @@ -2145,7 +2145,7 @@ parse_datetime2 (struct timespec *result, char const *p, || INT_ADD_WRAPV (tm.tm_mon, pc.rel.month, &month) || INT_ADD_WRAPV (tm.tm_mday, pc.rel.day, &day)) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: %s:%d\n"), __FILE__, __LINE__); goto fail; } @@ -2159,7 +2159,7 @@ parse_datetime2 (struct timespec *result, char const *p, Start = mktime_z (tz, &tm); if (Start == (time_t) -1) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: adding relative date resulted " "in an invalid date: '%s'\n"), debug_strfdatetime (&tm, &pc, dbg_tm, @@ -2167,7 +2167,7 @@ parse_datetime2 (struct timespec *result, char const *p, goto fail; } - if (pc.parse_datetime_debug) + if (debugging (&pc)) { dbg_printf (_("after date adjustment " "(%+"PRIdMAX" years, %+"PRIdMAX" months, " @@ -2244,7 +2244,7 @@ parse_datetime2 (struct timespec *result, char const *p, overflow |= INT_SUBTRACT_WRAPV (Start, delta, &t1); if (overflow) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: timezone %d caused time_t overflow\n"), pc.time_zone); goto fail; @@ -2252,7 +2252,7 @@ parse_datetime2 (struct timespec *result, char const *p, Start = t1; } - if (pc.parse_datetime_debug) + if (debugging (&pc)) { intmax_t Starti = Start; dbg_printf (_("'%s' = %"PRIdMAX" epoch-seconds\n"), @@ -2282,7 +2282,7 @@ parse_datetime2 (struct timespec *result, char const *p, || INT_ADD_WRAPV (t2, pc.rel.seconds, &t3) || INT_ADD_WRAPV (t3, d4, &t4)) { - if (pc.parse_datetime_debug) + if (debugging (&pc)) dbg_printf (_("error: adding relative time caused an " "overflow\n")); goto fail; @@ -2291,7 +2291,7 @@ parse_datetime2 (struct timespec *result, char const *p, result->tv_sec = t4; result->tv_nsec = normalized_ns; - if (pc.parse_datetime_debug + if (debugging (&pc) && (pc.rel.hour | pc.rel.minutes | pc.rel.seconds | pc.rel.ns)) { dbg_printf (_("after time adjustment (%+"PRIdMAX" hours, " @@ -2322,7 +2322,7 @@ parse_datetime2 (struct timespec *result, char const *p, } } - if (pc.parse_datetime_debug) + if (debugging (&pc)) { /* Special case: using 'date -u' simply set TZ=UTC0 */ if (! tzstring) @@ -2373,6 +2373,36 @@ parse_datetime2 (struct timespec *result, char const *p, return ok; } +#ifdef GNULIB_PARSE_DATETIME2 +/* Parse a date/time string, storing the resulting time value into *RESULT. + The string itself is pointed to by P. Return true if successful. + P can be an incomplete or relative time specification; if so, use + *NOW as the basis for the returned time. Default to timezone + TZDEFAULT, which corresponds to tzalloc (TZSTRING). */ +bool +parse_datetime2 (struct timespec *result, char const *p, + struct timespec const *now, unsigned int flags, + timezone_t tzdefault, char const *tzstring) +{ + return parse_datetime_body (result, p, now, flags, tzdefault, tzstring); +} +#endif + + +/* The plain interface: run with debug=false and the default timezone. */ +bool +parse_datetime (struct timespec *result, char const *p, + struct timespec const *now) +{ + char const *tzstring = getenv ("TZ"); + timezone_t tz = tzalloc (tzstring); + if (!tz) + return false; + bool ok = parse_datetime_body (result, p, now, 0, tz, tzstring); + tzfree (tz); + return ok; +} + #if TEST int diff --git a/lib/passfd.c b/lib/passfd.c index ca10ba5..a993f39 100644 --- a/lib/passfd.c +++ b/lib/passfd.c @@ -142,19 +142,23 @@ recvfd (int sock, int flags) cmsg->cmsg_len = CMSG_LEN (sizeof fd); /* Initialize the payload: */ memcpy (CMSG_DATA (cmsg), &fd, sizeof fd); - msg.msg_controllen = cmsg->cmsg_len; + msg.msg_controllen = CMSG_SPACE (sizeof fd); len = recvmsg (sock, &msg, flags_recvmsg); if (len < 0) return -1; - + if (len == 0) + { + /* fake errno: at end the file is not available */ + errno = ENOTCONN; + return -1; + } cmsg = CMSG_FIRSTHDR (&msg); /* be paranoiac */ - if (len == 0 || cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd) + if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { - /* fake errno: at end the file is not available */ - errno = len ? EACCES : ENOTCONN; + errno = EACCES; return -1; } diff --git a/lib/rawmemchr.c b/lib/rawmemchr.c index bbb250f..f4d5030 100644 --- a/lib/rawmemchr.c +++ b/lib/rawmemchr.c @@ -19,6 +19,9 @@ /* Specification. */ #include <string.h> +/* A function definition is only needed if HAVE_RAWMEMCHR is not defined. */ +#if !HAVE_RAWMEMCHR + /* Find the first occurrence of C in S. */ void * rawmemchr (const void *s, int c_in) @@ -134,3 +137,5 @@ rawmemchr (const void *s, int c_in) char_ptr++; return (void *) char_ptr; } + +#endif diff --git a/lib/realloc.c b/lib/realloc.c index 35caeab..51d8d21 100644 --- a/lib/realloc.c +++ b/lib/realloc.c @@ -37,7 +37,11 @@ #include <stdlib.h> -#include <errno.h> +/* A function definition is only needed if NEED_REALLOC_GNU is defined above + or if the module 'realloc-posix' requests it. */ +#if NEED_REALLOC_GNU || (GNULIB_REALLOC_POSIX && !HAVE_REALLOC_POSIX) + +# include <errno.h> /* Change the size of an allocated block of memory P to N bytes, with error checking. If N is zero, change it to 1. If P is NULL, @@ -48,7 +52,7 @@ rpl_realloc (void *p, size_t n) { void *result; -#if NEED_REALLOC_GNU +# if NEED_REALLOC_GNU if (n == 0) { n = 1; @@ -57,23 +61,25 @@ rpl_realloc (void *p, size_t n) free (p); p = NULL; } -#endif +# endif if (p == NULL) { -#if GNULIB_REALLOC_GNU && !NEED_REALLOC_GNU && !SYSTEM_MALLOC_GLIBC_COMPATIBLE +# if GNULIB_REALLOC_GNU && !NEED_REALLOC_GNU && !SYSTEM_MALLOC_GLIBC_COMPATIBLE if (n == 0) n = 1; -#endif +# endif result = malloc (n); } else result = realloc (p, n); -#if !HAVE_REALLOC_POSIX +# if !HAVE_REALLOC_POSIX if (result == NULL) errno = ENOMEM; -#endif +# endif return result; } + +#endif diff --git a/lib/regcomp.c b/lib/regcomp.c index d93698a..887e5b5 100644 --- a/lib/regcomp.c +++ b/lib/regcomp.c @@ -1695,12 +1695,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) reg_errcode_t err; Idx i; re_node_set eclosure; - bool ok; bool incomplete = false; err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); if (__glibc_unlikely (err != REG_NOERROR)) return err; + /* An epsilon closure includes itself. */ + eclosure.elems[eclosure.nelem++] = node; + /* This indicates that we are calculating this node now. We reference this value to avoid infinite loop. */ dfa->eclosures[node].nelem = -1; @@ -1753,10 +1755,6 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) } } - /* An epsilon closure includes itself. */ - ok = re_node_set_insert (&eclosure, node); - if (__glibc_unlikely (! ok)) - return REG_ESPACE; if (incomplete && !root) dfa->eclosures[node].nelem = 0; else diff --git a/lib/regex_internal.c b/lib/regex_internal.c index 9dd387e..55f6b66 100644 --- a/lib/regex_internal.c +++ b/lib/regex_internal.c @@ -1314,6 +1314,7 @@ re_node_set_insert (re_node_set *set, Idx elem) { for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) set->elems[idx] = set->elems[idx - 1]; + DEBUG_ASSERT (set->elems[idx - 1] < elem); } /* Insert the new element. */ diff --git a/lib/regex_internal.h b/lib/regex_internal.h index 3fa2bf1..4b0a3ef 100644 --- a/lib/regex_internal.h +++ b/lib/regex_internal.h @@ -32,7 +32,10 @@ #include <stdbool.h> #include <stdint.h> -#include <dynarray.h> +#ifndef _LIBC +# include <dynarray.h> +#endif + #include <intprops.h> #include <verify.h> diff --git a/lib/regexec.c b/lib/regexec.c index f7b4f9c..6309dea 100644 --- a/lib/regexec.c +++ b/lib/regexec.c @@ -59,7 +59,7 @@ static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, Idx cur_idx, Idx nmatch); static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, Idx nregs, - regmatch_t *regs, + regmatch_t *regs, regmatch_t *prevregs, re_node_set *eps_via_nodes); static reg_errcode_t set_regs (const regex_t *preg, const re_match_context_t *mctx, @@ -186,7 +186,8 @@ static reg_errcode_t extend_buffers (re_match_context_t *mctx, int min_len); REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. - We return 0 if we find a match and REG_NOMATCH if not. */ + Return 0 if a match is found, REG_NOMATCH if not, REG_BADPAT if + EFLAGS is invalid. */ int regexec (const regex_t *__restrict preg, const char *__restrict string, @@ -269,8 +270,8 @@ compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); strings.) On success, re_match* functions return the length of the match, re_search* - return the position of the start of the match. Return value -1 means no - match was found and -2 indicates an internal error. */ + return the position of the start of the match. They return -1 on + match failure, -2 on error. */ regoff_t re_match (struct re_pattern_buffer *bufp, const char *string, Idx length, @@ -1206,27 +1207,26 @@ check_halt_state_context (const re_match_context_t *mctx, /* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA corresponding to the DFA). Return the destination node, and update EPS_VIA_NODES; - return -1 in case of errors. */ + return -1 on match failure, -2 on error. */ static Idx proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, + regmatch_t *prevregs, Idx *pidx, Idx node, re_node_set *eps_via_nodes, struct re_fail_stack_t *fs) { const re_dfa_t *const dfa = mctx->dfa; - Idx i; - bool ok; if (IS_EPSILON_NODE (dfa->nodes[node].type)) { re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; re_node_set *edests = &dfa->edests[node]; - Idx dest_node; - ok = re_node_set_insert (eps_via_nodes, node); + bool ok = re_node_set_insert (eps_via_nodes, node); if (__glibc_unlikely (! ok)) return -2; - /* Pick up a valid destination, or return -1 if none - is found. */ - for (dest_node = -1, i = 0; i < edests->nelem; ++i) + + /* Pick a valid destination, or return -1 if none is found. */ + Idx dest_node = -1; + for (Idx i = 0; i < edests->nelem; i++) { Idx candidate = edests->elems[i]; if (!re_node_set_contains (cur_nodes, candidate)) @@ -1244,7 +1244,7 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, /* Otherwise, push the second epsilon-transition on the fail stack. */ else if (fs != NULL && push_fail_stack (fs, *pidx, candidate, nregs, regs, - eps_via_nodes)) + prevregs, eps_via_nodes)) return -2; /* We know we are going to exit. */ @@ -1288,7 +1288,7 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, if (naccepted == 0) { Idx dest_node; - ok = re_node_set_insert (eps_via_nodes, node); + bool ok = re_node_set_insert (eps_via_nodes, node); if (__glibc_unlikely (! ok)) return -2; dest_node = dfa->edests[node].elems[0]; @@ -1317,7 +1317,8 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, static reg_errcode_t __attribute_warn_unused_result__ push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, - Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) + Idx nregs, regmatch_t *regs, regmatch_t *prevregs, + re_node_set *eps_via_nodes) { reg_errcode_t err; Idx num = fs->num++; @@ -1333,25 +1334,30 @@ push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, } fs->stack[num].idx = str_idx; fs->stack[num].node = dest_node; - fs->stack[num].regs = re_malloc (regmatch_t, nregs); + fs->stack[num].regs = re_malloc (regmatch_t, 2 * nregs); if (fs->stack[num].regs == NULL) return REG_ESPACE; memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); + memcpy (fs->stack[num].regs + nregs, prevregs, sizeof (regmatch_t) * nregs); err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); return err; } static Idx pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, - regmatch_t *regs, re_node_set *eps_via_nodes) + regmatch_t *regs, regmatch_t *prevregs, + re_node_set *eps_via_nodes) { + if (fs == NULL || fs->num == 0) + return -1; Idx num = --fs->num; - DEBUG_ASSERT (num >= 0); *pidx = fs->stack[num].idx; memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); + memcpy (prevregs, fs->stack[num].regs + nregs, sizeof (regmatch_t) * nregs); re_node_set_free (eps_via_nodes); re_free (fs->stack[num].regs); *eps_via_nodes = fs->stack[num].eps_via_nodes; + DEBUG_ASSERT (0 <= fs->stack[num].node); return fs->stack[num].node; } @@ -1407,33 +1413,32 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, { update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); - if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) + if ((idx == pmatch[0].rm_eo && cur_node == mctx->last_node) + || re_node_set_contains (&eps_via_nodes, cur_node)) { Idx reg_idx; + cur_node = -1; if (fs) { for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) - break; - if (reg_idx == nmatch) - { - re_node_set_free (&eps_via_nodes); - regmatch_list_free (&prev_match); - return free_fail_stack_return (fs); - } - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); + { + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + prev_idx_match, &eps_via_nodes); + break; + } } - else + if (cur_node < 0) { re_node_set_free (&eps_via_nodes); regmatch_list_free (&prev_match); - return REG_NOERROR; + return free_fail_stack_return (fs); } } /* Proceed to next node. */ - cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, + cur_node = proceed_next_node (mctx, nmatch, pmatch, prev_idx_match, + &idx, cur_node, &eps_via_nodes, fs); if (__glibc_unlikely (cur_node < 0)) @@ -1445,13 +1450,13 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, free_fail_stack_return (fs); return REG_ESPACE; } - if (fs) - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); - else + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + prev_idx_match, &eps_via_nodes); + if (cur_node < 0) { re_node_set_free (&eps_via_nodes); regmatch_list_free (&prev_match); + free_fail_stack_return (fs); return REG_NOMATCH; } } @@ -1495,10 +1500,10 @@ update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, } else if (type == OP_CLOSE_SUBEXP) { + /* We are at the last node of this sub expression. */ Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; if (reg_num < nmatch) { - /* We are at the last node of this sub expression. */ if (pmatch[reg_num].rm_so < cur_idx) { pmatch[reg_num].rm_eo = cur_idx; @@ -2195,6 +2200,7 @@ sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, /* Return the next state to which the current state STATE will transit by accepting the current input byte, and update STATE_LOG if necessary. + Return NULL on failure. If STATE can accept a multibyte char/collating element/back reference update the destination of STATE_LOG. */ @@ -2395,7 +2401,7 @@ check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, #if 0 /* Return the next state to which the current state STATE will transit by - accepting the current input byte. */ + accepting the current input byte. Return NULL on failure. */ static re_dfastate_t * transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, @@ -2817,7 +2823,8 @@ find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, /* Check whether the node TOP_NODE at TOP_STR can arrive to the node LAST_NODE at LAST_STR. We record the path onto PATH since it will be heavily reused. - Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ + Return REG_NOERROR if it can arrive, REG_NOMATCH if it cannot, + REG_ESPACE if memory is exhausted. */ static reg_errcode_t __attribute_warn_unused_result__ @@ -3433,7 +3440,8 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) /* Group all nodes belonging to STATE into several destinations. Then for all destinations, set the nodes belonging to the destination to DESTS_NODE[i] and set the characters accepted by the destination - to DEST_CH[i]. This function return the number of destinations. */ + to DEST_CH[i]. Return the number of destinations if successful, + -1 on internal error. */ static Idx group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, @@ -4211,7 +4219,8 @@ match_ctx_add_subtop (re_match_context_t *mctx, Idx node, Idx str_idx) } /* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches - at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ + at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. + Return the new entry if successful, NULL if memory is exhausted. */ static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx) diff --git a/lib/relocwrapper.c b/lib/relocwrapper.c index 0624bd9..771da89 100644 --- a/lib/relocwrapper.c +++ b/lib/relocwrapper.c @@ -29,10 +29,26 @@ -> readlink -> stat -> canonicalize-lgpl + -> libc-config + -> errno + -> fcntl-h + -> stdbool + -> sys_stat + -> unistd + -> eloop-threshold -> filename - -> malloca - -> lstat + -> idx + -> intprops + -> scratch_buffer + -> malloc-posix + -> realloc-posix + -> free-posix + -> pathmax + -> mempcpy + -> rawmemchr -> readlink + -> stat + -> double-slash-root -> relocatable -> setenv -> malloca diff --git a/lib/scratch_buffer.h b/lib/scratch_buffer.h index 603b0d6..f4b5f9e 100644 --- a/lib/scratch_buffer.h +++ b/lib/scratch_buffer.h @@ -19,6 +19,97 @@ #ifndef _GL_SCRATCH_BUFFER_H #define _GL_SCRATCH_BUFFER_H +/* Scratch buffers with a default stack allocation and fallback to + heap allocation. It is expected that this function is used in this + way: + + struct scratch_buffer tmpbuf; + scratch_buffer_init (&tmpbuf); + + while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length)) + if (!scratch_buffer_grow (&tmpbuf)) + return -1; + + scratch_buffer_free (&tmpbuf); + return 0; + + The allocation functions (scratch_buffer_grow, + scratch_buffer_grow_preserve, scratch_buffer_set_array_size) make + sure that the heap allocation, if any, is freed, so that the code + above does not have a memory leak. The buffer still remains in a + state that can be deallocated using scratch_buffer_free, so a loop + like this is valid as well: + + struct scratch_buffer tmpbuf; + scratch_buffer_init (&tmpbuf); + + while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length)) + if (!scratch_buffer_grow (&tmpbuf)) + break; + + scratch_buffer_free (&tmpbuf); + + scratch_buffer_grow and scratch_buffer_grow_preserve are guaranteed + to grow the buffer by at least 512 bytes. This means that when + using the scratch buffer as a backing store for a non-character + array whose element size, in bytes, is 512 or smaller, the scratch + buffer only has to grow once to make room for at least one more + element. +*/ + +/* Scratch buffer. Must be initialized with scratch_buffer_init + before its use. */ +struct scratch_buffer; + +/* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space + and BUFFER->length reflects the available space. */ +#if 0 +extern void scratch_buffer_init (struct scratch_buffer *buffer); +#endif + +/* Deallocates *BUFFER (if it was heap-allocated). */ +#if 0 +extern void scratch_buffer_free (struct scratch_buffer *buffer); +#endif + +/* Grow *BUFFER by some arbitrary amount. The buffer contents is NOT + preserved. Return true on success, false on allocation failure (in + which case the old buffer is freed). On success, the new buffer is + larger than the previous size. On failure, *BUFFER is deallocated, + but remains in a free-able state, and errno is set. */ +#if 0 +extern bool scratch_buffer_grow (struct scratch_buffer *buffer); +#endif + +/* Like scratch_buffer_grow, but preserve the old buffer + contents on success, as a prefix of the new buffer. */ +#if 0 +extern bool scratch_buffer_grow_preserve (struct scratch_buffer *buffer); +#endif + +/* Grow *BUFFER so that it can store at least NELEM elements of SIZE + bytes. The buffer contents are NOT preserved. Both NELEM and SIZE + can be zero. Return true on success, false on allocation failure + (in which case the old buffer is freed, but *BUFFER remains in a + free-able state, and errno is set). It is unspecified whether this + function can reduce the array size. */ +#if 0 +extern bool scratch_buffer_set_array_size (struct scratch_buffer *buffer, + size_t nelem, size_t size); +#endif + +/* Return a copy of *BUFFER's first SIZE bytes as a heap-allocated block, + deallocating *BUFFER if it was heap-allocated. SIZE must be at + most *BUFFER's size. Return NULL (setting errno) on memory + exhaustion. */ +#if 0 +extern void *scratch_buffer_dupfree (struct scratch_buffer *buffer, + size_t size); +#endif + + +/* The implementation is imported from glibc. */ + #include <libc-config.h> #define __libc_scratch_buffer_dupfree gl_scratch_buffer_dupfree diff --git a/lib/simple-atomic.c b/lib/simple-atomic.c new file mode 100644 index 0000000..7c4f7e9 --- a/dev/null +++ b/lib/simple-atomic.c @@ -0,0 +1,360 @@ +/* Simple atomic operations for multithreading. + Copyright (C) 2020-2021 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 2, 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#include <config.h> + +/* Specification. */ +#include "simple-atomic.h" + +#if defined _WIN32 && ! defined __CYGWIN__ +/* Native Windows. */ + +# include <windows.h> + +void +memory_barrier (void) +{ + /* MemoryBarrier + <https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-memorybarrier> */ + MemoryBarrier (); +} + +unsigned int +atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval) +{ + /* InterlockedCompareExchange + <https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchange> */ + return InterlockedCompareExchange ((LONG volatile *) vp, + (LONG) newval, (LONG) cmp); +} + +uintptr_t +atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval) +{ + /* InterlockedCompareExchangePointer + <https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchangepointer> */ + return InterlockedCompareExchangePointer ((void * volatile *) vp, + (void *) newval, (void *) cmp); +} + +#elif HAVE_PTHREAD_H +/* Some other platform that supports multi-threading. + + We don't use the C11 <stdatomic.h> (available in GCC >= 4.9) because it would + require to link with -latomic. */ + +# if (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \ + && !defined __sparc__) \ + || __clang_major__ >= 3) \ + && !defined __ibmxl__ +/* Use GCC built-ins (available in GCC >= 4.1, except on SPARC, and + clang >= 3.0). + Documentation: + <https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html> */ + +void +memory_barrier (void) +{ + __sync_synchronize (); +} + +unsigned int +atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval) +{ + return __sync_val_compare_and_swap (vp, cmp, newval); +} + +uintptr_t +atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval) +{ + return __sync_val_compare_and_swap (vp, cmp, newval); +} + +# elif defined _AIX +/* AIX */ +/* For older versions of GCC or xlc, use inline assembly. + __compare_and_swap and __compare_and_swaplp are not sufficient here. */ + +void +memory_barrier (void) +{ + asm volatile ("sync"); +} + +unsigned int +atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval) +{ + asm volatile ("sync"); + + unsigned int oldval; + asm volatile ( +# if defined __GNUC__ || defined __clang__ + "1: lwarx %0,0,%1\n" + " cmpw 0,%0,%2\n" + " bne 0,2f\n" + " stwcx. %3,0,%1\n" + " bne 0,1b\n" + "2:" +# else /* another label syntax */ + ".L01: lwarx %0,0,%1\n" + " cmpw 0,%0,%2\n" + " bne 0,.L02\n" + " stwcx. %3,0,%1\n" + " bne 0,.L01\n" + ".L02:" +# endif + : "=&r" (oldval) + : "r" (vp), "r" (cmp), "r" (newval) + : "cr0"); + + asm volatile ("isync"); + return oldval; +} + +uintptr_t +atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval) +{ + asm volatile ("sync"); + + uintptr_t oldval; + asm volatile ( +# if defined __GNUC__ || defined __clang__ +# if defined __powerpc64__ || defined __LP64__ + "1: ldarx %0,0,%1\n" + " cmpd 0,%0,%2\n" + " bne 0,2f\n" + " stdcx. %3,0,%1\n" + " bne 0,1b\n" + "2:" +# else + "1: lwarx %0,0,%1\n" + " cmpw 0,%0,%2\n" + " bne 0,2f\n" + " stwcx. %3,0,%1\n" + " bne 0,1b\n" + "2:" +# endif +# else /* another label syntax */ +# if defined __powerpc64__ || defined __LP64__ + ".L01: ldarx %0,0,%1\n" + " cmpd 0,%0,%2\n" + " bne 0,.L02\n" + " stdcx. %3,0,%1\n" + " bne 0,.L01\n" + ".L02:" +# else + ".L01: lwarx %0,0,%1\n" + " cmpw 0,%0,%2\n" + " bne 0,.L02\n" + " stwcx. %3,0,%1\n" + " bne 0,.L01\n" + ".L02:" +# endif +# endif + : "=&r" (oldval) + : "r" (vp), "r" (cmp), "r" (newval) + : "cr0"); + + asm volatile ("isync"); + return oldval; +} + +# elif ((defined __GNUC__ || defined __clang__ || defined __SUNPRO_C) && (defined __sparc || defined __i386 || defined __x86_64__)) || (defined __TINYC__ && (defined __i386 || defined __x86_64__)) +/* For older versions of GCC or clang, use inline assembly. + GCC, clang, and the Oracle Studio C 12 compiler understand GCC's extended + asm syntax, but the plain Oracle Studio C 11 compiler understands only + simple asm. */ + +void +memory_barrier (void) +{ +# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 || defined __TINYC__ +# if defined __i386 || defined __x86_64__ +# if defined __TINYC__ && defined __i386 + /* Cannot use the SSE instruction "mfence" with this compiler. */ + asm volatile ("lock orl $0,(%esp)"); +# else + asm volatile ("mfence"); +# endif +# endif +# if defined __sparc + asm volatile ("membar 2"); +# endif +# else +# if defined __i386 || defined __x86_64__ + asm ("mfence"); +# endif +# if defined __sparc + asm ("membar 2"); +# endif +# endif +} + +unsigned int +atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval) +{ +# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 || defined __TINYC__ + unsigned int oldval; +# if defined __i386 || defined __x86_64__ + asm volatile (" lock\n cmpxchgl %3,(%1)" + : "=a" (oldval) : "r" (vp), "a" (cmp), "r" (newval) : "memory"); +# endif +# if defined __sparc + asm volatile (" cas [%1],%2,%3\n" + " mov %3,%0" + : "=r" (oldval) : "r" (vp), "r" (cmp), "r" (newval) : "memory"); +# endif + return oldval; +# else /* __SUNPRO_C */ +# if defined __x86_64__ + asm (" movl %esi,%eax\n" + " lock\n cmpxchgl %edx,(%rdi)"); +# elif defined __i386 + asm (" movl 16(%ebp),%ecx\n" + " movl 12(%ebp),%eax\n" + " movl 8(%ebp),%edx\n" + " lock\n cmpxchgl %ecx,(%edx)"); +# endif +# if defined __sparc + asm (" cas [%i0],%i1,%i2\n" + " mov %i2,%i0"); +# endif +# endif +} + +uintptr_t +atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval) +{ +# if defined __GNUC__ || defined __clang__ || __SUNPRO_C >= 0x590 || defined __TINYC__ + uintptr_t oldval; +# if defined __x86_64__ + asm volatile (" lock\n cmpxchgq %3,(%1)" + : "=a" (oldval) : "r" (vp), "a" (cmp), "r" (newval) : "memory"); +# elif defined __i386 + asm volatile (" lock\n cmpxchgl %3,(%1)" + : "=a" (oldval) : "r" (vp), "a" (cmp), "r" (newval) : "memory"); +# endif +# if defined __sparc && (defined __sparcv9 || defined __arch64__) + asm volatile (" casx [%1],%2,%3\n" + " mov %3,%0" + : "=r" (oldval) : "r" (vp), "r" (cmp), "r" (newval) : "memory"); +# elif defined __sparc + asm volatile (" cas [%1],%2,%3\n" + " mov %3,%0" + : "=r" (oldval) : "r" (vp), "r" (cmp), "r" (newval) : "memory"); +# endif + return oldval; +# else /* __SUNPRO_C */ +# if defined __x86_64__ + asm (" movl %rsi,%rax\n" + " lock\n cmpxchgq %rdx,(%rdi)"); +# elif defined __i386 + asm (" movl 16(%ebp),%ecx\n" + " movl 12(%ebp),%eax\n" + " movl 8(%ebp),%edx\n" + " lock\n cmpxchgl %ecx,(%edx)"); +# endif +# if defined __sparc && (defined __sparcv9 || defined __arch64__) + asm (" casx [%i0],%i1,%i2\n" + " mov %i2,%i0"); +# elif defined __sparc + asm (" cas [%i0],%i1,%i2\n" + " mov %i2,%i0"); +# endif +# endif +} + +# else +/* Fallback code. It has some race conditions. The unit test will fail. */ + +void +memory_barrier (void) +{ +} + +unsigned int +atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval) +{ + unsigned int oldval = *vp; + if (oldval == cmp) + *vp = newval; + return oldval; +} + +uintptr_t +atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval) +{ + uintptr_t oldval = *vp; + if (oldval == cmp) + *vp = newval; + return oldval; +} + +# endif + +#else +/* A platform that does not support multi-threading. */ + +void +memory_barrier (void) +{ +} + +unsigned int +atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval) +{ + unsigned int oldval = *vp; + if (oldval == cmp) + *vp = newval; + return oldval; +} + +uintptr_t +atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval) +{ + uintptr_t oldval = *vp; + if (oldval == cmp) + *vp = newval; + return oldval; +} + +#endif diff --git a/lib/simple-atomic.h b/lib/simple-atomic.h new file mode 100644 index 0000000..5a34e66 --- a/dev/null +++ b/lib/simple-atomic.h @@ -0,0 +1,49 @@ +/* Simple atomic operations for multithreading. + Copyright (C) 2021 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 2, 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#ifndef _SIMPLE_ATOMIC_H +#define _SIMPLE_ATOMIC_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Guarantees that memory stores that are in code before this call + are finished before this call, and that memory loads that are in code + after this call are started after this call. */ +extern void memory_barrier (void); + +/* Stores NEWVAL in *VP if the old value *VP is == CMP. + Returns the old value. */ +extern unsigned int atomic_compare_and_swap (unsigned int volatile *vp, + unsigned int cmp, + unsigned int newval); + +/* Stores NEWVAL in *VP if the old value *VP is == CMP. + Returns the old value. */ +extern uintptr_t atomic_compare_and_swap_ptr (uintptr_t volatile *vp, + uintptr_t cmp, + uintptr_t newval); + +#ifdef __cplusplus +} +#endif + +#endif /* _SIMPLE_ATOMIC_H */ diff --git a/lib/stddef.in.h b/lib/stddef.in.h index 5d3e087..590e12c 100644 --- a/lib/stddef.in.h +++ b/lib/stddef.in.h @@ -42,6 +42,15 @@ # define _GL_STDDEF_WINT_T # endif # @INCLUDE_NEXT@ @NEXT_STDDEF_H@ + /* On TinyCC, make sure that the macros that indicate the special invocation + convention get undefined. */ +# ifdef __TINYC__ +# undef __need_wchar_t +# undef __need_size_t +# undef __need_ptrdiff_t +# undef __need_NULL +# undef __need_wint_t +# endif # endif #else @@ -51,7 +60,7 @@ /* On AIX 7.2, with xlc in 64-bit mode, <stddef.h> defines max_align_t to a type with alignment 4, but 'long' has alignment 8. */ -# if defined _AIX && defined _ARCH_PPC64 +# if defined _AIX && defined __LP64__ # if !GNULIB_defined_max_align_t # ifdef _MAX_ALIGN_T /* /usr/include/stddef.h has already defined max_align_t. Override it. */ @@ -109,7 +118,7 @@ typedef long max_align_t; && defined __cplusplus # include <cstddef> #else -# if ! (@HAVE_MAX_ALIGN_T@ || defined _GCC_MAX_ALIGN_T) +# if ! (@HAVE_MAX_ALIGN_T@ || (defined _GCC_MAX_ALIGN_T && !defined __clang__)) # if !GNULIB_defined_max_align_t /* On the x86, the maximum storage alignment of double, long, etc. is 4, but GCC's C11 ABI for x86 says that max_align_t has an alignment of 8, diff --git a/lib/string-buffer.c b/lib/string-buffer.c new file mode 100644 index 0000000..b5a4009 --- a/dev/null +++ b/lib/string-buffer.c @@ -0,0 +1,297 @@ +/* A buffer that accumulates a string by piecewise concatenation. + Copyright (C) 2021 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 2, 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#include <config.h> + +/* Specification. */ +#include "string-buffer.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void +sb_init (struct string_buffer *buffer) +{ + buffer->data = buffer->space; + buffer->length = 0; + buffer->allocated = sizeof (buffer->space); + buffer->error = false; +} + +/* Ensures that INCREMENT bytes are available beyond the current used length + of BUFFER. + Returns 0, or -1 in case of out-of-memory error. */ +static int +sb_ensure_more_bytes (struct string_buffer *buffer, size_t increment) +{ + size_t incremented_length = buffer->length + increment; + if (incremented_length < increment) + /* Overflow. */ + return -1; + + if (buffer->allocated < incremented_length) + { + size_t new_allocated = 2 * buffer->allocated; + if (new_allocated < buffer->allocated) + /* Overflow. */ + return -1; + if (new_allocated < incremented_length) + new_allocated = incremented_length; + + char *new_data; + if (buffer->data == buffer->space) + { + new_data = (char *) malloc (new_allocated); + if (new_data == NULL) + /* Out-of-memory. */ + return -1; + memcpy (new_data, buffer->data, buffer->length); + } + else + { + new_data = (char *) realloc (buffer->data, new_allocated); + if (new_data == NULL) + /* Out-of-memory. */ + return -1; + } + buffer->data = new_data; + buffer->allocated = new_allocated; + } + return 0; +} + +int +sb_append (struct string_buffer *buffer, const char *str) +{ + size_t len = strlen (str); + if (sb_ensure_more_bytes (buffer, len) < 0) + { + buffer->error = true; + return -1; + } + memcpy (buffer->data + buffer->length, str, len); + buffer->length += len; + return 0; +} + +int +sb_appendvf (struct string_buffer *buffer, const char *formatstring, + va_list list) +{ + va_list list_copy; + + /* Make a bit of room, so that the probability that the first vsnprintf() call + succeeds is high. */ + size_t room = buffer->allocated - buffer->length; + if (room < 64) + { + if (sb_ensure_more_bytes (buffer, 64) < 0) + { + buffer->error = true; + return -1; + } + room = buffer->allocated - buffer->length; + } + + va_copy (list_copy, list); + + /* First vsnprintf() call. */ + int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, list); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + { + /* The result was truncated. Make more room, for a second vsnprintf() + call. */ + if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0) + { + buffer->error = true; + ret = -1; + } + else + { + /* Second vsnprintf() call. */ + room = buffer->allocated - buffer->length; + ret = vsnprintf (buffer->data + buffer->length, room, + formatstring, list_copy); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + /* The return values of the vsnprintf() calls are not + consistent. */ + abort (); + } + } + } + } + + va_end (list_copy); + return ret; +} + +int +sb_appendf (struct string_buffer *buffer, const char *formatstring, ...) +{ + va_list args; + + /* Make a bit of room, so that the probability that the first vsnprintf() call + succeeds is high. */ + size_t room = buffer->allocated - buffer->length; + if (room < 64) + { + if (sb_ensure_more_bytes (buffer, 64) < 0) + { + buffer->error = true; + return -1; + } + room = buffer->allocated - buffer->length; + } + + va_start (args, formatstring); + + /* First vsnprintf() call. */ + int ret = vsnprintf (buffer->data + buffer->length, room, formatstring, args); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + { + /* The result was truncated. Make more room, for a second vsnprintf() + call. */ + if (sb_ensure_more_bytes (buffer, (size_t) ret) < 0) + { + buffer->error = true; + ret = -1; + } + else + { + /* Second vsnprintf() call. */ + room = buffer->allocated - buffer->length; + va_end (args); + va_start (args, formatstring); + ret = vsnprintf (buffer->data + buffer->length, room, + formatstring, args); + if (ret < 0) + { + /* Failed. */ + buffer->error = true; + ret = -1; + } + else + { + if ((size_t) ret <= room) + { + /* The result has fit into room bytes. */ + buffer->length += (size_t) ret; + ret = 0; + } + else + /* The return values of the vsnprintf() calls are not + consistent. */ + abort (); + } + } + } + } + + va_end (args); + return ret; +} + +void +sb_free (struct string_buffer *buffer) +{ + if (buffer->data != buffer->space) + free (buffer->data); +} + +/* Returns the contents of BUFFER, and frees all other memory held + by BUFFER. Returns NULL upon failure or if there was an error earlier. */ +char * +sb_dupfree (struct string_buffer *buffer) +{ + if (buffer->error) + goto fail; + + if (sb_ensure_more_bytes (buffer, 1) < 0) + goto fail; + buffer->data[buffer->length] = '\0'; + buffer->length++; + + if (buffer->data == buffer->space) + { + char *copy = (char *) malloc (buffer->length); + if (copy == NULL) + goto fail; + memcpy (copy, buffer->data, buffer->length); + return copy; + } + else + { + /* Shrink the string before returning it. */ + char *contents = buffer->data; + if (buffer->length < buffer->allocated) + { + contents = realloc (contents, buffer->length); + if (contents == NULL) + goto fail; + } + return contents; + } + + fail: + sb_free (buffer); + return NULL; +} diff --git a/lib/string-buffer.h b/lib/string-buffer.h new file mode 100644 index 0000000..6beaff5 --- a/dev/null +++ b/lib/string-buffer.h @@ -0,0 +1,85 @@ +/* A buffer that accumulates a string by piecewise concatenation. + Copyright (C) 2021 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 2, 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#ifndef _STRING_BUFFER_H +#define _STRING_BUFFER_H + +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> + +#include "attribute.h" + +/* A string buffer type. */ +struct string_buffer +{ + char *data; + size_t length; /* used bytes, <= allocated */ + size_t allocated; /* allocated bytes */ + bool error; /* true if there was an error */ + char space[1024]; /* stack allocated space */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializes BUFFER to the empty string. */ +extern void sb_init (struct string_buffer *buffer); + +/* Appends the contents of STR to BUFFER. + Returns 0, or -1 in case of out-of-memory error. */ +extern int sb_append (struct string_buffer *buffer, const char *str); + +/* Appends the result of the printf-compatible FORMATSTRING with the argument + list LIST to BUFFER. + Returns 0, or -1 in case of error. */ +extern int sb_appendvf (struct string_buffer *buffer, + const char *formatstring, va_list list) + #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) + ATTRIBUTE_FORMAT ((__gnu_printf__, 2, 0)) + #else + ATTRIBUTE_FORMAT ((__printf__, 2, 0)) + #endif + ; + +/* Appends the result of the printf-compatible FORMATSTRING with the following + arguments to BUFFER. + Returns 0, or -1 in case of error. */ +extern int sb_appendf (struct string_buffer *buffer, + const char *formatstring, ...) + #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) + ATTRIBUTE_FORMAT ((__gnu_printf__, 2, 3)) + #else + ATTRIBUTE_FORMAT ((__printf__, 2, 3)) + #endif + ; + +/* Frees the memory held by BUFFER. */ +extern void sb_free (struct string_buffer *buffer); + +/* Returns the contents of BUFFER, and frees all other memory held + by BUFFER. Returns NULL upon failure or if there was an error earlier. + It is the responsibility of the caller to free() the result. */ +extern char * sb_dupfree (struct string_buffer *buffer); + +#ifdef __cplusplus +} +#endif + +#endif /* _STRING_BUFFER_H */ diff --git a/lib/unlocked-io.h b/lib/unlocked-io.h index 86b91c1..ca184b3 100644 --- a/lib/unlocked-io.h +++ b/lib/unlocked-io.h @@ -33,91 +33,91 @@ # include <stdio.h> -# if HAVE_DECL_CLEARERR_UNLOCKED +# if HAVE_DECL_CLEARERR_UNLOCKED || defined clearerr_unlocked # undef clearerr # define clearerr(x) clearerr_unlocked (x) # else # define clearerr_unlocked(x) clearerr (x) # endif -# if HAVE_DECL_FEOF_UNLOCKED +# if HAVE_DECL_FEOF_UNLOCKED || defined feof_unlocked # undef feof # define feof(x) feof_unlocked (x) # else # define feof_unlocked(x) feof (x) # endif -# if HAVE_DECL_FERROR_UNLOCKED +# if HAVE_DECL_FERROR_UNLOCKED || defined ferror_unlocked # undef ferror # define ferror(x) ferror_unlocked (x) # else # define ferror_unlocked(x) ferror (x) # endif -# if HAVE_DECL_FFLUSH_UNLOCKED +# if HAVE_DECL_FFLUSH_UNLOCKED || defined fflush_unlocked # undef fflush # define fflush(x) fflush_unlocked (x) # else # define fflush_unlocked(x) fflush (x) # endif -# if HAVE_DECL_FGETS_UNLOCKED +# if HAVE_DECL_FGETS_UNLOCKED || defined fgets_unlocked # undef fgets # define fgets(x,y,z) fgets_unlocked (x,y,z) # else # define fgets_unlocked(x,y,z) fgets (x,y,z) # endif -# if HAVE_DECL_FPUTC_UNLOCKED +# if HAVE_DECL_FPUTC_UNLOCKED || defined fputc_unlocked # undef fputc # define fputc(x,y) fputc_unlocked (x,y) # else # define fputc_unlocked(x,y) fputc (x,y) # endif -# if HAVE_DECL_FPUTS_UNLOCKED +# if HAVE_DECL_FPUTS_UNLOCKED || defined fputs_unlocked # undef fputs # define fputs(x,y) fputs_unlocked (x,y) # else # define fputs_unlocked(x,y) fputs (x,y) # endif -# if HAVE_DECL_FREAD_UNLOCKED +# if HAVE_DECL_FREAD_UNLOCKED || defined fread_unlocked # undef fread # define fread(w,x,y,z) fread_unlocked (w,x,y,z) # else # define fread_unlocked(w,x,y,z) fread (w,x,y,z) # endif -# if HAVE_DECL_FWRITE_UNLOCKED +# if HAVE_DECL_FWRITE_UNLOCKED || defined fwrite_unlocked # undef fwrite # define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) # else # define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) # endif -# if HAVE_DECL_GETC_UNLOCKED +# if HAVE_DECL_GETC_UNLOCKED || defined get_unlocked # undef getc # define getc(x) getc_unlocked (x) # else # define getc_unlocked(x) getc (x) # endif -# if HAVE_DECL_GETCHAR_UNLOCKED +# if HAVE_DECL_GETCHAR_UNLOCKED || defined getchar_unlocked # undef getchar # define getchar() getchar_unlocked () # else # define getchar_unlocked() getchar () # endif -# if HAVE_DECL_PUTC_UNLOCKED +# if HAVE_DECL_PUTC_UNLOCKED || defined putc_unlocked # undef putc # define putc(x,y) putc_unlocked (x,y) # else # define putc_unlocked(x,y) putc (x,y) # endif -# if HAVE_DECL_PUTCHAR_UNLOCKED +# if HAVE_DECL_PUTCHAR_UNLOCKED || defined putchar_unlocked # undef putchar # define putchar(x) putchar_unlocked (x) # else diff --git a/m4/c-stack.m4 b/m4/c-stack.m4 index e7413a2..df8dc52 100644 --- a/m4/c-stack.m4 +++ b/m4/c-stack.m4 @@ -7,7 +7,7 @@ # Written by Paul Eggert. -# serial 20 +# serial 21 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC], [ @@ -19,7 +19,7 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC], dnl is accessed, or when the stack overflows. dnl Either { SIGSEGV } or { SIGSEGV, SIGBUS }. case "$host_os" in - sunos4* | freebsd* | dragonfly* | openbsd* | mirbsd* | netbsd* | kfreebsd* | knetbsd*) # BSD systems + sunos4* | freebsd* | dragonfly* | midnightbsd* | openbsd* | mirbsd* | netbsd* | kfreebsd* | knetbsd*) # BSD systems FAULT_YIELDS_SIGBUS=1 ;; hpux*) # HP-UX FAULT_YIELDS_SIGBUS=1 ;; @@ -1,4 +1,4 @@ -# expl.m4 serial 17 +# expl.m4 serial 18 dnl Copyright (C) 2010-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -129,7 +129,7 @@ int main (int argc, char *argv[]) if (isnan (expl (x1)) || isnan (expl (x2)) || isnan (expl (x3))) result |= 2; } - /* This test fails on NetBSD 9.0. */ + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x, NetBSD 9.0. */ { const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) @@ -150,8 +150,8 @@ int main (int argc, char *argv[]) [case "$host_os" in # Guess yes on glibc systems. *-gnu* | gnu*) gl_cv_func_expl_works="guessing yes" ;; - # Guess yes on musl systems. - *-musl*) gl_cv_func_expl_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_expl_works="guessing no" ;; # Guess yes on native Windows. mingw*) gl_cv_func_expl_works="guessing yes" ;; # If we don't know, obey --enable-cross-guesses. diff --git a/m4/expm1l.m4 b/m4/expm1l.m4 index 0eaaf84..ec0d907 100644 --- a/m4/expm1l.m4 +++ b/m4/expm1l.m4 @@ -1,4 +1,4 @@ -# expm1l.m4 serial 7 +# expm1l.m4 serial 9 dnl Copyright (C) 2010-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -123,7 +123,8 @@ int main (int argc, char *argv[]) { long double (* volatile my_expm1l) (long double) = argc ? expm1l : dummy; int result = 0; - /* This test fails on Mac OS X 10.5, NetBSD 8.0. */ + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x, Mac OS X 10.5, + NetBSD 8.0. */ { const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) @@ -134,7 +135,8 @@ int main (int argc, char *argv[]) long double x = 11.358L; long double y = my_expm1l (x); long double z = my_expm1l (- x); - long double err = (y + (1.0L + y) * z) * TWO_LDBL_MANT_DIG; + volatile long double t = (1.0L + y) * z; + long double err = (y + t) * TWO_LDBL_MANT_DIG; if (!(err >= -100.0L && err <= 100.0L)) result |= 1; } @@ -146,8 +148,8 @@ int main (int argc, char *argv[]) [case "$host_os" in # Guess yes on glibc systems. *-gnu* | gnu*) gl_cv_func_expm1l_works="guessing yes" ;; - # Guess yes on musl systems. - *-musl*) gl_cv_func_expm1l_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_expm1l_works="guessing no" ;; # Guess yes on native Windows. mingw*) gl_cv_func_expm1l_works="guessing yes" ;; # If we don't know, obey --enable-cross-guesses. @@ -1,4 +1,4 @@ -# free.m4 serial 5 +# free.m4 serial 6 # Copyright (C) 2003-2005, 2009-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -40,7 +40,10 @@ AC_DEFUN([gl_FUNC_FREE], ]) case $gl_cv_func_free_preserves_errno in - *yes) ;; + *yes) + AC_DEFINE([HAVE_FREE_POSIX], [1], + [Define if the 'free' function is guaranteed to preserve errno.]) + ;; *) REPLACE_FREE=1 ;; esac ]) diff --git a/m4/getcwd-abort-bug.m4 b/m4/getcwd-abort-bug.m4 index 89d0689..bd32de1 100644 --- a/m4/getcwd-abort-bug.m4 +++ b/m4/getcwd-abort-bug.m4 @@ -1,4 +1,4 @@ -# serial 15 +# serial 16 # Determine whether getcwd aborts when the length of the working directory # name is unusually large. Any length between 4k and 16k trigger the bug # when using glibc-2.4.90-9 or older. @@ -128,11 +128,12 @@ main () ]])], [gl_cv_func_getcwd_succeeds_beyond_4k=yes], [dnl An abort will provoke an exit code of something like 134 (128 + 6). - dnl An exit code of 4 can also occur (in OpenBSD 6.7, NetBSD 5.1 for - dnl example): getcwd (NULL, 0) fails rather than returning a string - dnl longer than PATH_MAX. This may be POSIX compliant (in some - dnl interpretations of POSIX). But gnulib's getcwd module wants to - dnl provide a non-NULL value in this case. + dnl An exit code of 4 can also occur (for example in + dnl musl libc 1.2.2/powerpc64le, NetBSD 9.0, OpenBSD 6.7: + dnl getcwd (NULL, 0) fails rather than returning a string longer than + dnl PATH_MAX. This may be POSIX compliant (in some interpretations of + dnl POSIX). But gnulib's getcwd module wants to provide a non-NULL + dnl value in this case. ret=$? if test $ret -ge 128 || test $ret = 4; then gl_cv_func_getcwd_succeeds_beyond_4k=no @@ -141,10 +142,8 @@ main () fi ], [case "$host_os" in - # Guess yes on musl systems. - *-musl*) gl_cv_func_getcwd_succeeds_beyond_4k="guessing yes" ;; - # Guess no otherwise, even on glibc systems. - *) gl_cv_func_getcwd_succeeds_beyond_4k="guessing no" + # Guess no otherwise, even on glibc systems and musl systems. + *) gl_cv_func_getcwd_succeeds_beyond_4k="guessing no" esac ]) ]) diff --git a/m4/host-cpu-c-abi.m4 b/m4/host-cpu-c-abi.m4 index 7dc830e..64e28b1 100644 --- a/m4/host-cpu-c-abi.m4 +++ b/m4/host-cpu-c-abi.m4 @@ -1,4 +1,4 @@ -# host-cpu-c-abi.m4 serial 13 +# host-cpu-c-abi.m4 serial 14 dnl Copyright (C) 2002-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -211,7 +211,7 @@ changequote([,])dnl # be generating 64-bit code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( - [[#if defined __powerpc64__ || defined _ARCH_PPC64 + [[#if defined __powerpc64__ || defined __LP64__ int ok; #else error fail @@ -605,7 +605,7 @@ changequote([,])dnl # be generating 64-bit code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( - [[#if defined __powerpc64__ || defined _ARCH_PPC64 + [[#if defined __powerpc64__ || defined __LP64__ int ok; #else error fail diff --git a/m4/host-os.m4 b/m4/host-os.m4 index 543473c..813133b 100644 --- a/m4/host-os.m4 +++ b/m4/host-os.m4 @@ -1,4 +1,4 @@ -# serial 10 +# serial 11 # Copyright (C) 2001, 2003-2004, 2006, 2009-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -41,6 +41,7 @@ AC_DEFUN([gl_HOST_OS], netbsd*-gnu*) os='GNU/NetBSD';; # NetBSD kernel+libc, GNU userland netbsd*) os='NetBSD';; mirbsd*) os='MirBSD';; + midnightbsd*) os='MidnightBSD';; knetbsd*-gnu) os='GNU/kNetBSD';; # NetBSD kernel, GNU libc+userland kfreebsd*-gnu) os='GNU/kFreeBSD';; # FreeBSD kernel, GNU libc+userland msdosdjgpp*) os='DJGPP';; diff --git a/m4/lib-ld.m4 b/m4/lib-ld.m4 index aa07cb4..076358d 100644 --- a/m4/lib-ld.m4 +++ b/m4/lib-ld.m4 @@ -1,4 +1,4 @@ -# lib-ld.m4 serial 9 +# lib-ld.m4 serial 10 dnl Copyright (C) 1996-2003, 2009-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -122,7 +122,7 @@ else *-*-aix*) AC_COMPILE_IFELSE( [AC_LANG_SOURCE( - [[#if defined __powerpc64__ || defined _ARCH_PPC64 + [[#if defined __powerpc64__ || defined __LP64__ int ok; #else error fail diff --git a/m4/log10l.m4 b/m4/log10l.m4 index c594f6b..57aa1ba 100644 --- a/m4/log10l.m4 +++ b/m4/log10l.m4 @@ -1,4 +1,4 @@ -# log10l.m4 serial 9 +# log10l.m4 serial 10 dnl Copyright (C) 2011-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -126,7 +126,7 @@ int main (int argc, char *argv[]) if (!(gy + gy == gy)) result |= 1; } - /* This test fails on NetBSD 9.0. */ + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x, NetBSD 9.0. */ { const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) @@ -147,8 +147,8 @@ int main (int argc, char *argv[]) [case "$host_os" in # Guess yes on glibc systems. *-gnu* | gnu*) gl_cv_func_log10l_works="guessing yes" ;; - # Guess yes on musl systems. - *-musl*) gl_cv_func_log10l_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_log10l_works="guessing no" ;; # Guess yes on native Windows. mingw*) gl_cv_func_log10l_works="guessing yes" ;; # If we don't know, obey --enable-cross-guesses. diff --git a/m4/log1pl.m4 b/m4/log1pl.m4 index 7d95aac..bd9d63d 100644 --- a/m4/log1pl.m4 +++ b/m4/log1pl.m4 @@ -1,4 +1,4 @@ -# log1pl.m4 serial 8 +# log1pl.m4 serial 9 dnl Copyright (C) 2012-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -22,6 +22,16 @@ AC_DEFUN([gl_FUNC_LOG1PL], LIBS="$save_LIBS" if test $ac_cv_func_log1pl = yes; then LOG1PL_LIBM="$LOG1P_LIBM" + + save_LIBS="$LIBS" + LIBS="$LIBS $LOG1PL_LIBM" + gl_FUNC_LOG1PL_WORKS + LIBS="$save_LIBS" + case "$gl_cv_func_log1pl_works" in + *yes) ;; + *) REPLACE_LOG1PL=1 ;; + esac + m4_ifdef([gl_FUNC_LOG1PL_IEEE], [ if test $gl_log1pl_required = ieee && test $REPLACE_LOG1PL = 0; then AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles @@ -99,3 +109,93 @@ int main (int argc, char *argv[]) fi AC_SUBST([LOG1PL_LIBM]) ]) + +dnl Test whether log1pl() works. +dnl On musl 1.2.2/{arm64,s390x}, the result is accurate to only 16 digits. +AC_DEFUN([gl_FUNC_LOG1PL_WORKS], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether log1pl works], [gl_cv_func_log1pl_works], + [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#ifndef __NO_MATH_INLINES +# define __NO_MATH_INLINES 1 /* for glibc */ +#endif +#include <float.h> +#include <math.h> +/* Override the values of <float.h>, like done in float.in.h. */ +#if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 64 +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP (-16381) +# undef LDBL_MAX_EXP +# define LDBL_MAX_EXP 16384 +#endif +#if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 64 +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP (-16381) +# undef LDBL_MAX_EXP +# define LDBL_MAX_EXP 16384 +#endif +#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__ +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +#endif +#if defined __sgi && (LDBL_MANT_DIG >= 106) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 106 +# if defined __GNUC__ +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +# endif +#endif +#undef log1pl +extern +#ifdef __cplusplus +"C" +#endif +long double log1pl (long double); +static long double dummy (long double x) { return 0; } +int main (int argc, char *argv[]) +{ + long double (* volatile my_log1pl) (long double) = argc ? log1pl : dummy; + int result = 0; + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x. */ + { + const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ + (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 1) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 2) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 3) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 4) / 5)); + long double x = 11.358L; + long double y = my_log1pl (x); + long double z = my_log1pl (- x / (1.0L + x)); + long double err = (y + z) * TWO_LDBL_MANT_DIG; + if (!(err >= -900.0L && err <= 900.0L)) + result |= 1; + } + + return result; +} +]])], + [gl_cv_func_log1pl_works=yes], + [gl_cv_func_log1pl_works=no], + [case "$host_os" in + # Guess yes on glibc systems. + *-gnu* | gnu*) gl_cv_func_log1pl_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_log1pl_works="guessing no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_log1pl_works="guessing yes" ;; + # If we don't know, obey --enable-cross-guesses. + *) gl_cv_func_log1pl_works="$gl_cross_guess_normal" ;; + esac + ]) + ]) +]) diff --git a/m4/log2l.m4 b/m4/log2l.m4 index 4776543..cd8e984 100644 --- a/m4/log2l.m4 +++ b/m4/log2l.m4 @@ -1,4 +1,4 @@ -# log2l.m4 serial 2 +# log2l.m4 serial 3 dnl Copyright (C) 2010-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -69,6 +69,7 @@ AC_DEFUN([gl_FUNC_LOG2L], dnl Test whether log2l() works. dnl On OSF/1 5.1, log2l(-0.0) is NaN. +dnl On musl 1.2.2/{arm64,s390x}, the result is accurate to only 16 digits. AC_DEFUN([gl_FUNC_LOG2L_WORKS], [ AC_REQUIRE([AC_PROG_CC]) @@ -77,7 +78,40 @@ AC_DEFUN([gl_FUNC_LOG2L_WORKS], [ AC_RUN_IFELSE( [AC_LANG_SOURCE([[ +#ifndef __NO_MATH_INLINES +# define __NO_MATH_INLINES 1 /* for glibc */ +#endif +#include <float.h> #include <math.h> +/* Override the values of <float.h>, like done in float.in.h. */ +#if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 64 +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP (-16381) +# undef LDBL_MAX_EXP +# define LDBL_MAX_EXP 16384 +#endif +#if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 64 +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP (-16381) +# undef LDBL_MAX_EXP +# define LDBL_MAX_EXP 16384 +#endif +#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__ +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +#endif +#if defined __sgi && (LDBL_MANT_DIG >= 106) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 106 +# if defined __GNUC__ +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +# endif +#endif #ifndef log2l /* for AIX */ extern #ifdef __cplusplus @@ -85,25 +119,59 @@ extern #endif long double log2l (long double); #endif -volatile long double x; -volatile long double y; -int main () +static long double dummy (long double x) { return 0; } +volatile long double gx; +volatile long double gy; +int main (int argc, char *argv[]) { + long double (* volatile my_log2l) (long double) = argc ? log2l : dummy; + int result = 0; /* This test fails on OSF/1 5.1. */ - x = -0.0L; - y = log2l (x); - if (!(y + y == y)) - return 1; - return 0; + { + gx = -0.0L; + gy = my_log2l (gx); + if (!(gy + gy == gy)) + result |= 1; + } + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x. */ + { + const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ + (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 1) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 2) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 3) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 4) / 5)); + long double x = 11.358L; + long double y = my_log2l (x); + long double z = my_log2l (1.0L / x); + long double err = (y + z) * TWO_LDBL_MANT_DIG; + if (!(err >= -10000.0L && err <= 10000.0L)) + result |= 2; + } + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x. */ + if (DBL_MAX_EXP < LDBL_MAX_EXP) + { + long double x = ldexpl (1.0L, DBL_MAX_EXP); /* finite! */ + long double y = my_log2l (x); + if (y > 0 && y + y == y) /* infinite? */ + result |= 4; + } + return result; } ]])], [gl_cv_func_log2l_works=yes], [gl_cv_func_log2l_works=no], [case "$host_os" in - osf*) gl_cv_func_log2l_works="guessing no" ;; - # Guess yes on native Windows. - mingw*) gl_cv_func_log2l_works="guessing yes" ;; - *) gl_cv_func_log2l_works="guessing yes" ;; + # Guess yes on glibc systems. + *-gnu* | gnu*) gl_cv_func_log2l_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_log2l_works="guessing no" ;; + # Guess no on OSF/1. + osf*) gl_cv_func_log2l_works="guessing no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_log2l_works="guessing yes" ;; + # If we don't know, obey --enable-cross-guesses. + *) gl_cv_func_log2l_works="$gl_cross_guess_normal" ;; esac ]) ]) @@ -1,4 +1,4 @@ -# logl.m4 serial 14 +# logl.m4 serial 15 dnl Copyright (C) 2010-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -166,7 +166,7 @@ int main (int argc, char *argv[]) if (!(gy + gy == gy)) result |= 1; } - /* This test fails on NetBSD 9.0. */ + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x, NetBSD 9.0. */ { const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) @@ -188,8 +188,8 @@ int main (int argc, char *argv[]) [case "$host_os" in # Guess yes on glibc systems. *-gnu* | gnu*) gl_cv_func_logl_works="guessing yes" ;; - # Guess yes on musl systems. - *-musl*) gl_cv_func_logl_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_logl_works="guessing no" ;; # Guess yes on native Windows. mingw*) gl_cv_func_logl_works="guessing yes" ;; # If we don't know, obey --enable-cross-guesses. diff --git a/m4/malloc.m4 b/m4/malloc.m4 index 514d19a..32ab42e 100644 --- a/m4/malloc.m4 +++ b/m4/malloc.m4 @@ -1,4 +1,4 @@ -# malloc.m4 serial 21 +# malloc.m4 serial 22 dnl Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -24,7 +24,7 @@ AC_DEFUN([_AC_FUNC_MALLOC_IF], [ac_cv_func_malloc_0_nonnull=no], [case "$host_os" in # Guess yes on platforms where we know the result. - *-gnu* | gnu* | *-musl* | freebsd* | netbsd* | openbsd* \ + *-gnu* | gnu* | *-musl* | freebsd* | midnightbsd* | netbsd* | openbsd* \ | hpux* | solaris* | cygwin* | mingw*) ac_cv_func_malloc_0_nonnull="guessing yes" ;; # If we don't know, obey --enable-cross-guesses. diff --git a/m4/mbrtoc32.m4 b/m4/mbrtoc32.m4 index 56f09c6..ba0397b 100644 --- a/m4/mbrtoc32.m4 +++ b/m4/mbrtoc32.m4 @@ -1,4 +1,4 @@ -# mbrtoc32.m4 serial 6 +# mbrtoc32.m4 serial 7 dnl Copyright (C) 2014-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -158,7 +158,7 @@ AC_DEFUN([gl_MBRTOC32_SANITYCHECK], changequote(,)dnl case "$host_os" in # Guess no on FreeBSD, Solaris, native Windows. - freebsd* | solaris* | mingw*) + freebsd* | midnightbsd* | solaris* | mingw*) gl_cv_func_mbrtoc32_sanitycheck="guessing no" ;; # Guess yes otherwise. diff --git a/m4/mprotect.m4 b/m4/mprotect.m4 index 13e27e2..9a0bdf9 100644 --- a/m4/mprotect.m4 +++ b/m4/mprotect.m4 @@ -1,4 +1,4 @@ -# mprotect.m4 serial 1 +# mprotect.m4 serial 2 dnl Copyright (C) 1993-2021 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License as published by the Free Software Foundation; @@ -141,7 +141,7 @@ AC_DEFUN([gl_FUNC_MPROTECT_WORKS], dnl Guess yes on Linux systems, glibc systems, dnl macOS, BSD systems, AIX, HP-UX, IRIX, Solaris, Cygwin. linux-* | linux | *-gnu* | gnu* | \ - darwin* | freebsd* | dragonfly* | netbsd* | openbsd* | \ + darwin* | freebsd* | dragonfly* | midnightbsd* | netbsd* | openbsd* | \ aix* | hpux* | irix* | solaris* | cygwin*) gl_cv_func_mprotect_works="guessing yes" ;; mingw*) diff --git a/m4/posix_spawn.m4 b/m4/posix_spawn.m4 index 787336d..84b7a13 100644 --- a/m4/posix_spawn.m4 +++ b/m4/posix_spawn.m4 @@ -1,4 +1,4 @@ -# posix_spawn.m4 serial 19 +# posix_spawn.m4 serial 21 dnl Copyright (C) 2008-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -525,7 +525,8 @@ AC_DEFUN([gl_POSIX_SPAWN_SECURE], *-gnu* | *-musl* | netbsd*) gl_cv_func_posix_spawnp_secure_exec="guessing yes" ;; # Guess no on GNU/Hurd, macOS, FreeBSD, OpenBSD, AIX, Solaris, Cygwin. - gnu* | darwin* | freebsd* | dragonfly* | openbsd* | aix* | solaris* | cygwin*) + gnu* | darwin* | freebsd* | dragonfly* | midnightbsd* | openbsd* | \ + aix* | solaris* | cygwin*) gl_cv_func_posix_spawnp_secure_exec="guessing no" ;; # If we don't know, obey --enable-cross-guesses. *) @@ -552,8 +553,8 @@ AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE], if test $REPLACE_POSIX_SPAWN = 1; then REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 else - dnl On musl libc and Solaris 11.0, posix_spawn_file_actions_addclose - dnl succeeds even if the fd argument is out of range. + dnl On musl libc, posix_spawn_file_actions_addclose succeeds even if the fd + dnl argument is negative. AC_CACHE_CHECK([whether posix_spawn_file_actions_addclose works], [gl_cv_func_posix_spawn_file_actions_addclose_works], [AC_RUN_IFELSE( @@ -564,7 +565,7 @@ int main () posix_spawn_file_actions_t actions; if (posix_spawn_file_actions_init (&actions) != 0) return 1; - if (posix_spawn_file_actions_addclose (&actions, 10000000) == 0) + if (posix_spawn_file_actions_addclose (&actions, -5) == 0) return 2; return 0; }]])], diff --git a/m4/printf.m4 b/m4/printf.m4 index c8e74e2..d8b3521 100644 --- a/m4/printf.m4 +++ b/m4/printf.m4 @@ -1,4 +1,4 @@ -# printf.m4 serial 71 +# printf.m4 serial 72 dnl Copyright (C) 2003, 2007-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -67,6 +67,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 5. freebsd[1-4].*) gl_cv_func_printf_sizes_c99="guessing no";; freebsd* | kfreebsd*) gl_cv_func_printf_sizes_c99="guessing yes";; + midnightbsd*) gl_cv_func_printf_sizes_c99="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_printf_sizes_c99="guessing no";; darwin*) gl_cv_func_printf_sizes_c99="guessing yes";; @@ -247,6 +248,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 6. freebsd[1-5].*) gl_cv_func_printf_infinite="guessing no";; freebsd* | kfreebsd*) gl_cv_func_printf_infinite="guessing yes";; + midnightbsd*) gl_cv_func_printf_infinite="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_printf_infinite="guessing no";; darwin*) gl_cv_func_printf_infinite="guessing yes";; @@ -469,6 +471,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 6. freebsd[1-5].*) gl_cv_func_printf_infinite_long_double="guessing no";; freebsd* | kfreebsd*) gl_cv_func_printf_infinite_long_double="guessing yes";; + midnightbsd*) gl_cv_func_printf_infinite_long_double="guessing yes";; # Guess yes on HP-UX >= 11. hpux[7-9]* | hpux10*) gl_cv_func_printf_infinite_long_double="guessing no";; hpux*) gl_cv_func_printf_infinite_long_double="guessing yes";; @@ -644,6 +647,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 6. freebsd[1-5].*) gl_cv_func_printf_directive_f="guessing no";; freebsd* | kfreebsd*) gl_cv_func_printf_directive_f="guessing yes";; + midnightbsd*) gl_cv_func_printf_directive_f="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_printf_directive_f="guessing no";; darwin*) gl_cv_func_printf_directive_f="guessing yes";; @@ -1239,6 +1243,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 5. freebsd[1-4].*) gl_cv_func_snprintf_truncation_c99="guessing no";; freebsd* | kfreebsd*) gl_cv_func_snprintf_truncation_c99="guessing yes";; + midnightbsd*) gl_cv_func_snprintf_truncation_c99="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_snprintf_truncation_c99="guessing no";; darwin*) gl_cv_func_snprintf_truncation_c99="guessing yes";; @@ -1343,6 +1348,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 5. freebsd[1-4].*) gl_cv_func_snprintf_retval_c99="guessing no";; freebsd* | kfreebsd*) gl_cv_func_snprintf_retval_c99="guessing yes";; + midnightbsd*) gl_cv_func_snprintf_retval_c99="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_snprintf_retval_c99="guessing no";; darwin*) gl_cv_func_snprintf_retval_c99="guessing yes";; @@ -1445,6 +1451,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 5. freebsd[1-4].*) gl_cv_func_snprintf_directive_n="guessing no";; freebsd* | kfreebsd*) gl_cv_func_snprintf_directive_n="guessing yes";; + midnightbsd*) gl_cv_func_snprintf_directive_n="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_snprintf_directive_n="guessing no";; darwin*) gl_cv_func_snprintf_directive_n="guessing yes";; @@ -1601,6 +1608,7 @@ changequote(,)dnl # Guess yes on FreeBSD >= 5. freebsd[1-4].*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";; freebsd* | kfreebsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; + midnightbsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; # Guess yes on Mac OS X >= 10.3. darwin[1-6].*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";; darwin*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; diff --git a/m4/pthread_sigmask.m4 b/m4/pthread_sigmask.m4 index eb4c784..7c74415 100644 --- a/m4/pthread_sigmask.m4 +++ b/m4/pthread_sigmask.m4 @@ -1,4 +1,4 @@ -# pthread_sigmask.m4 serial 19 +# pthread_sigmask.m4 serial 20 dnl Copyright (C) 2011-2021 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,9 +111,9 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles - dnl On FreeBSD 6.4, HP-UX 11.31, Solaris 9, in programs that are not linked - dnl with -lpthread, the pthread_sigmask() function always returns 0 and has - dnl no effect. + dnl On FreeBSD 6.4, MidnightBSD 1.1, HP-UX 11.31, Solaris 9, in programs + dnl that are not linked with -lpthread, the pthread_sigmask() function + dnl always returns 0 and has no effect. if test -z "$LIB_PTHREAD_SIGMASK"; then case " $LIBS " in *' -pthread '*) ;; @@ -138,7 +138,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], [ changequote(,)dnl case "$host_os" in - freebsd* | hpux* | solaris | solaris2.[2-9]*) + freebsd* | midnightbsd* | hpux* | solaris | solaris2.[2-9]*) gl_cv_func_pthread_sigmask_in_libc_works="guessing no";; *) gl_cv_func_pthread_sigmask_in_libc_works="guessing yes";; diff --git a/m4/realloc.m4 b/m4/realloc.m4 index 6f4461d..a80a02a 100644 --- a/m4/realloc.m4 +++ b/m4/realloc.m4 @@ -1,4 +1,4 @@ -# realloc.m4 serial 19 +# realloc.m4 serial 20 dnl Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -24,7 +24,7 @@ AC_DEFUN([_AC_FUNC_REALLOC_IF], [ac_cv_func_realloc_0_nonnull=no], [case "$host_os" in # Guess yes on platforms where we know the result. - *-gnu* | gnu* | *-musl* | freebsd* | netbsd* | openbsd* \ + *-gnu* | gnu* | *-musl* | freebsd* | midnightbsd* | netbsd* | openbsd* \ | hpux* | solaris* | cygwin* | mingw*) ac_cv_func_realloc_0_nonnull="guessing yes" ;; # If we don't know, obey --enable-cross-guesses. diff --git a/m4/relocatable.m4 b/m4/relocatable.m4 index a3bd41e..c11999e 100644 --- a/m4/relocatable.m4 +++ b/m4/relocatable.m4 @@ -1,4 +1,4 @@ -# relocatable.m4 serial 23 +# relocatable.m4 serial 24 dnl Copyright (C) 2003, 2005-2007, 2009-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -68,10 +68,11 @@ AC_DEFUN([gl_RELOCATABLE_BODY], fi ;; changequote(,)dnl - # FreeBSD >= 7.3, DragonFly >= 3.0: yes. + # FreeBSD >= 7.3, DragonFly >= 3.0, MidnightBSD >= 1.1: yes. freebsd | freebsd[1-7] | freebsd[1-6].* | freebsd7.[0-2]) ;; dragonfly | dragonfly[1-2] | dragonfly[1-2].*) ;; - freebsd* | dragonfly*) use_elf_origin_trick=yes ;; + midnightbsd | midnightbsd0* | midnightbsd1.0*) ;; + freebsd* | dragonfly* | midnightbsd*) use_elf_origin_trick=yes ;; # NetBSD >= 8.0: yes. netbsd | netbsd[1-7] | netbsd[1-7].*) ;; netbsdelf | netbsdelf[1-7] | netbsdelf[1-7].*) ;; diff --git a/m4/remainderl.m4 b/m4/remainderl.m4 index 395ad2a..4867f9c 100644 --- a/m4/remainderl.m4 +++ b/m4/remainderl.m4 @@ -1,4 +1,4 @@ -# remainderl.m4 serial 12 +# remainderl.m4 serial 13 dnl Copyright (C) 2012-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -153,6 +153,7 @@ int main (int argc, char *argv[]) dnl Test whether remainderl() works. dnl It produces completely wrong values on OpenBSD 5.1/SPARC. +dnl On musl 1.2.2/{arm64,s390x}, the result is accurate to only 16 digits. AC_DEFUN([gl_FUNC_REMAINDERL_WORKS], [ AC_REQUIRE([AC_PROG_CC]) @@ -164,33 +165,90 @@ AC_DEFUN([gl_FUNC_REMAINDERL_WORKS], #ifndef __NO_MATH_INLINES # define __NO_MATH_INLINES 1 /* for glibc */ #endif +#include <float.h> #include <math.h> +/* Override the values of <float.h>, like done in float.in.h. */ +#if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 64 +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP (-16381) +# undef LDBL_MAX_EXP +# define LDBL_MAX_EXP 16384 +#endif +#if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 64 +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP (-16381) +# undef LDBL_MAX_EXP +# define LDBL_MAX_EXP 16384 +#endif +#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__ +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +#endif +#if defined __sgi && (LDBL_MANT_DIG >= 106) +# undef LDBL_MANT_DIG +# define LDBL_MANT_DIG 106 +# if defined __GNUC__ +# undef LDBL_MIN_EXP +# define LDBL_MIN_EXP DBL_MIN_EXP +# endif +#endif extern #ifdef __cplusplus "C" #endif long double remainderl (long double, long double); -volatile long double x; -volatile long double y; -long double z; -int main () +static long double dummy (long double x, long double y) { return 0; } +volatile long double gx; +volatile long double gy; +long double gz; +int main (int argc, char *argv[]) { + long double (* volatile my_remainderl) (long double, long double) = + argc ? remainderl : dummy; + int result = 0; /* This test fails on OpenBSD 5.1/SPARC. */ - x = 9.245907126L; - y = 3.141592654L; - z = remainderl (x, y); - if (z >= 0.0L) - return 1; - return 0; + { + gx = 9.245907126L; + gy = 3.141592654L; + gz = remainderl (gx, gy); + if (gz >= 0.0L) + result |= 1; + } + /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x. */ + { + const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */ + (long double) (1U << ((LDBL_MANT_DIG - 1) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 1) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 2) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 3) / 5)) + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 4) / 5)); + long double x = 11.357996098166760874793827872740874983168L; + long double y = 0.486497838502717923110029188864352615388L; + long double z = my_remainderl (x, y) - (x - 23 * y); + long double err = z * TWO_LDBL_MANT_DIG; + if (!(err >= -32.0L && err <= 32.0L)) + result |= 2; + } + return result; } ]])], [gl_cv_func_remainderl_works=yes], [gl_cv_func_remainderl_works=no], [case "$host_os" in - openbsd*) gl_cv_func_remainderl_works="guessing no" ;; - # Guess yes on native Windows. - mingw*) gl_cv_func_remainderl_works="guessing yes" ;; - *) gl_cv_func_remainderl_works="guessing yes" ;; + # Guess yes on glibc systems. + *-gnu* | gnu*) gl_cv_func_remainderl_works="guessing yes" ;; + # Guess no on musl systems. + *-musl*) gl_cv_func_remainderl_works="guessing no" ;; + # Guess no on OpenBSD. + openbsd*) gl_cv_func_remainderl_works="guessing no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_remainderl_works="guessing yes" ;; + # If we don't know, obey --enable-cross-guesses. + *) gl_cv_func_remainderl_works="$gl_cross_guess_normal" ;; esac ]) ]) diff --git a/m4/setlocale_null.m4 b/m4/setlocale_null.m4 index c486ca8..2c958ed 100644 --- a/m4/setlocale_null.m4 +++ b/m4/setlocale_null.m4 @@ -1,4 +1,4 @@ -# setlocale_null.m4 serial 4 +# setlocale_null.m4 serial 5 dnl Copyright (C) 2019-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,7 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL], [gl_cv_func_setlocale_null_all_mtsafe], [case "$host_os" in # Guess no on musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin. - *-musl* | darwin* | freebsd* | netbsd* | openbsd* | aix* | haiku* | cygwin*) + *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | openbsd* | aix* | haiku* | cygwin*) gl_cv_func_setlocale_null_all_mtsafe=no ;; # Guess yes on glibc, HP-UX, IRIX, Solaris, native Windows. *-gnu* | gnu* | hpux* | irix* | solaris* | mingw*) @@ -48,7 +48,7 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL], openbsd* | aix*) gl_cv_func_setlocale_null_one_mtsafe=no ;; # Guess yes on glibc, musl libc, macOS, FreeBSD, NetBSD, HP-UX, IRIX, Solaris, Haiku, Cygwin, native Windows. - *-gnu* | gnu* | *-musl* | darwin* | freebsd* | netbsd* | hpux* | irix* | solaris* | haiku* | cygwin* | mingw*) + *-gnu* | gnu* | *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | hpux* | irix* | solaris* | haiku* | cygwin* | mingw*) gl_cv_func_setlocale_null_one_mtsafe=yes ;; # If we don't know, obey --enable-cross-guesses. *) diff --git a/m4/strfmon_l.m4 b/m4/strfmon_l.m4 index 32a78f0..e79ff97 100644 --- a/m4/strfmon_l.m4 +++ b/m4/strfmon_l.m4 @@ -1,4 +1,4 @@ -# strfmon_l.m4 serial 2 +# strfmon_l.m4 serial 3 dnl Copyright (C) 2017-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -40,7 +40,7 @@ AC_DEFUN([gl_FUNC_STRFMON_L], [gl_cv_strfmon_l_works="guessing yes"]) ;; # Guess no on FreeBSD and Cygwin. - freebsd* | cygwin*) gl_cv_strfmon_l_works="guessing no" ;; + freebsd* | midnightbsd* | cygwin*) gl_cv_strfmon_l_works="guessing no" ;; # Guess yes otherwise. *) gl_cv_strfmon_l_works="guessing yes" ;; esac diff --git a/m4/threadlib.m4 b/m4/threadlib.m4 index 20b383a..8fc3dfd 100644 --- a/m4/threadlib.m4 +++ b/m4/threadlib.m4 @@ -1,4 +1,4 @@ -# threadlib.m4 serial 29 +# threadlib.m4 serial 30 dnl Copyright (C) 2005-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -126,7 +126,7 @@ int main () case "$gl_cv_have_weak" in *yes) case "$host_os" in - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) : > conftest1.c $CC $CPPFLAGS $CFLAGS $LDFLAGS -fPIC -shared -o libempty.so conftest1.c -lpthread >&AS_MESSAGE_LOG_FD 2>&1 cat <<EOF > conftest2.c @@ -488,7 +488,7 @@ AC_DEFUN([gl_THREADLIB_BODY], LIBTHREAD= LTLIBTHREAD= else case "$host_os" in - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) if test "x$LIBTHREAD" != "x$LIBMULTITHREAD"; then dnl If weak symbols can't tell whether pthread_create(), pthread_key_create() dnl etc. will succeed, we need a runtime test. diff --git a/m4/utime.m4 b/m4/utime.m4 index 03df7b7..4ed4158 100644 --- a/m4/utime.m4 +++ b/m4/utime.m4 @@ -1,4 +1,4 @@ -# utime.m4 serial 3 +# utime.m4 serial 4 dnl Copyright (C) 2017-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -34,7 +34,7 @@ AC_DEFUN([gl_FUNC_UTIME], AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include <stddef.h> - #include <time.h> + #include <utime.h> ]], [[int result = 0; if (!utime ("conftest.tmp/", NULL)) diff --git a/m4/visibility.m4 b/m4/visibility.m4 index 6e4b461..8f27a12 100644 --- a/m4/visibility.m4 +++ b/m4/visibility.m4 @@ -1,4 +1,4 @@ -# visibility.m4 serial 6 +# visibility.m4 serial 7 dnl Copyright (C) 2005, 2008, 2010-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -58,6 +58,7 @@ AC_DEFUN([gl_VISIBILITY], extern __attribute__((__visibility__("default"))) int exportedvar; extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); extern __attribute__((__visibility__("default"))) int exportedfunc (void); + void dummyfunc (void); void dummyfunc (void) {} ]], [[]])], diff --git a/m4/wcwidth.m4 b/m4/wcwidth.m4 index 40fdea7..2ac2a51 100644 --- a/m4/wcwidth.m4 +++ b/m4/wcwidth.m4 @@ -1,4 +1,4 @@ -# wcwidth.m4 serial 33 +# wcwidth.m4 serial 34 dnl Copyright (C) 2006-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -41,8 +41,10 @@ AC_DEFUN([gl_FUNC_WCWIDTH], if test $ac_cv_func_wcwidth = yes || test $gl_cv_func_wcwidth_macro = yes; then HAVE_WCWIDTH=1 dnl On Mac OS X 10.3, wcwidth(0x0301) (COMBINING ACUTE ACCENT) returns 1. - dnl On NetBSD 9.0, OpenBSD 5.0, wcwidth(0x05B0) (HEBREW POINT SHEVA) returns 1. - dnl On NetBSD 9.0, OSF/1 5.1, wcwidth(0x200B) (ZERO WIDTH SPACE) returns 1. + dnl On NetBSD 9.0, OpenBSD 5.0, MidnightBSD 1.1, + dnl wcwidth(0x05B0) (HEBREW POINT SHEVA) returns 1. + dnl On NetBSD 9.0, MidnightBSD 1.1, OSF/1 5.1, + dnl wcwidth(0x200B) (ZERO WIDTH SPACE) returns 1. dnl On OpenBSD 5.8, wcwidth(0xFF1A) (FULLWIDTH COLON) returns 0. dnl This leads to bugs in 'ls' (coreutils). dnl On Solaris 11.4, wcwidth(0x2202) (PARTIAL DIFFERENTIAL) returns 2, diff --git a/modules/canonicalize b/modules/canonicalize index a6cf76f..ddd83bc 100644 --- a/modules/canonicalize +++ b/modules/canonicalize @@ -15,7 +15,6 @@ extensions fcntl-h file-set filename -free-posix getcwd hash-triple-simple idx @@ -29,7 +28,7 @@ scratch_buffer stat stdbool sys_stat -xalloc +unistd xalloc-die configure.ac: diff --git a/modules/canonicalize-lgpl b/modules/canonicalize-lgpl index b8e87a6..0bc5591 100644 --- a/modules/canonicalize-lgpl +++ b/modules/canonicalize-lgpl @@ -16,11 +16,9 @@ eloop-threshold [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONI errno [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] fcntl-h [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] filename [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] -free-posix [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] idx [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] intprops [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] libc-config [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] -malloc-posix [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] memmove [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] mempcpy [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] pathmax [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] @@ -30,6 +28,7 @@ scratch_buffer [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONI stat [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] stdbool [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] sys_stat [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] +unistd [test $HAVE_CANONICALIZE_FILE_NAME = 0 || test $REPLACE_CANONICALIZE_FILE_NAME = 1] configure.ac: gl_CANONICALIZE_LGPL diff --git a/modules/linked-list-tests b/modules/linked-list-tests index c34e49e..bf21bee 100644 --- a/modules/linked-list-tests +++ b/modules/linked-list-tests @@ -1,12 +1,20 @@ Files: tests/test-linked_list.c +tests/test-asyncsafe-linked_list.sh +tests/test-asyncsafe-linked_list.c tests/macros.h Depends-on: array-list +thread +yield +nanosleep +sigaction +sigprocmask configure.ac: Makefile.am: -TESTS += test-linked_list -check_PROGRAMS += test-linked_list +TESTS += test-linked_list test-asyncsafe-linked_list.sh +check_PROGRAMS += test-linked_list test-asyncsafe-linked_list +test_asyncsafe_linked_list_LDADD = $(LDADD) @LIBMULTITHREAD@ @YIELD_LIB@ diff --git a/modules/malloc-posix b/modules/malloc-posix index b5ab594..1a2d72c 100644 --- a/modules/malloc-posix +++ b/modules/malloc-posix @@ -14,6 +14,7 @@ if test $REPLACE_MALLOC = 1; then AC_LIBOBJ([malloc]) fi gl_STDLIB_MODULE_INDICATOR([malloc-posix]) +gl_MODULE_INDICATOR([malloc-posix]) Makefile.am: diff --git a/modules/parse-datetime b/modules/parse-datetime index 820bc6c..8a2d050 100644 --- a/modules/parse-datetime +++ b/modules/parse-datetime @@ -38,7 +38,7 @@ Makefile.am: # and by the GNU Coding Standards # <https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html> # the file should be generated in the source directory. -# - The #line numbers in the .c file refer to a nonexistent file once it +# - The #line directives in the .c file refer to a nonexistent file once it # has been moved from the build directory to the source directory. This # leads to error if 'lcov' is used later. # Additionally, here we assume GNU Bison and therefore don't need the ylwrap diff --git a/modules/parse-datetime2 b/modules/parse-datetime2 new file mode 100644 index 0000000..b4771dc --- a/dev/null +++ b/modules/parse-datetime2 @@ -0,0 +1,21 @@ +Description: +Convert a date/time string to linear time, with debugging. + +Files: + +Depends-on: +parse-datetime + +configure.ac: +AC_DEFINE([GNULIB_PARSE_DATETIME2], [1], [Define to support parse_datetime2.]) + +Makefile.am: + +Include: +"parse-datetime.h" + +License: +LGPLv2+ + +Maintainer: +Paul Eggert diff --git a/modules/posix_spawn_file_actions_addchdir-tests b/modules/posix_spawn_file_actions_addchdir-tests index 1c56b1c..e554138 100644 --- a/modules/posix_spawn_file_actions_addchdir-tests +++ b/modules/posix_spawn_file_actions_addchdir-tests @@ -6,6 +6,7 @@ tests/macros.h Depends-on: posix_spawn_file_actions_init +posix_spawn_file_actions_destroy posix_spawnp-tests findprog diff --git a/modules/posix_spawn_file_actions_addclose-tests b/modules/posix_spawn_file_actions_addclose-tests index 848acce..b115e3d 100644 --- a/modules/posix_spawn_file_actions_addclose-tests +++ b/modules/posix_spawn_file_actions_addclose-tests @@ -6,6 +6,7 @@ tests/macros.h Depends-on: getdtablesize posix_spawn_file_actions_init +posix_spawn_file_actions_destroy configure.ac: diff --git a/modules/posix_spawn_file_actions_adddup2-tests b/modules/posix_spawn_file_actions_adddup2-tests index f504892..5e25990 100644 --- a/modules/posix_spawn_file_actions_adddup2-tests +++ b/modules/posix_spawn_file_actions_adddup2-tests @@ -6,6 +6,7 @@ tests/macros.h Depends-on: getdtablesize posix_spawn_file_actions_init +posix_spawn_file_actions_destroy configure.ac: diff --git a/modules/posix_spawn_file_actions_addfchdir-tests b/modules/posix_spawn_file_actions_addfchdir-tests index 45f4230..2f09934 100644 --- a/modules/posix_spawn_file_actions_addfchdir-tests +++ b/modules/posix_spawn_file_actions_addfchdir-tests @@ -6,6 +6,7 @@ tests/macros.h Depends-on: posix_spawn_file_actions_init +posix_spawn_file_actions_destroy posix_spawnp-tests findprog diff --git a/modules/posix_spawn_file_actions_addopen-tests b/modules/posix_spawn_file_actions_addopen-tests index fbe7943..8f0de9e 100644 --- a/modules/posix_spawn_file_actions_addopen-tests +++ b/modules/posix_spawn_file_actions_addopen-tests @@ -6,6 +6,7 @@ tests/macros.h Depends-on: getdtablesize posix_spawn_file_actions_init +posix_spawn_file_actions_destroy configure.ac: diff --git a/modules/realloc-posix b/modules/realloc-posix index 8e4924d..7f48110 100644 --- a/modules/realloc-posix +++ b/modules/realloc-posix @@ -15,6 +15,7 @@ if test $REPLACE_REALLOC = 1; then AC_LIBOBJ([realloc]) fi gl_STDLIB_MODULE_INDICATOR([realloc-posix]) +gl_MODULE_INDICATOR([realloc-posix]) Makefile.am: diff --git a/modules/relocatable-prog-wrapper b/modules/relocatable-prog-wrapper index f97fdae..da9ad30 100644 --- a/modules/relocatable-prog-wrapper +++ b/modules/relocatable-prog-wrapper @@ -17,9 +17,19 @@ lib/allocator.c lib/readlink.c lib/stat.c lib/canonicalize-lgpl.c +lib/scratch_buffer.h +lib/malloc/scratch_buffer.h +lib/malloc/scratch_buffer_dupfree.c +lib/malloc/scratch_buffer_grow.c +lib/malloc/scratch_buffer_grow_preserve.c +lib/malloc/scratch_buffer_set_array_size.c +lib/malloc.c +lib/realloc.c +lib/free.c +lib/mempcpy.c +lib/rawmemchr.c lib/malloca.h lib/malloca.c -lib/lstat.c lib/relocatable.h lib/relocatable.c lib/setenv.c @@ -28,6 +38,7 @@ lib/c-ctype.c m4/largefile.m4 m4/malloca.m4 m4/canonicalize.m4 +m4/lstat.m4 m4/eealloc.m4 m4/environ.m4 m4/readlink.m4 @@ -35,19 +46,26 @@ m4/relocatable-lib.m4 m4/setenv.m4 Depends-on: -alloca-opt +c99 double-slash-root +eloop-threshold +environ errno +fcntl-h filename +idx +intprops largefile +libc-config pathmax ssize_t stdbool +stddef stdint stdlib -unistd -environ string +sys_stat +unistd verify xalloc-oversized @@ -58,6 +76,11 @@ configure.ac: AC_REQUIRE([AC_C_RESTRICT]) gl_FUNC_READLINK_SEPARATE gl_CANONICALIZE_LGPL_SEPARATE +gl_FUNC_MALLOC_POSIX +gl_FUNC_REALLOC_POSIX +gl_FUNC_FREE +gl_FUNC_MEMPCPY +gl_FUNC_RAWMEMCHR gl_MALLOCA gl_RELOCATABLE_LIBRARY gl_FUNC_SETENV_SEPARATE diff --git a/modules/scratch_buffer b/modules/scratch_buffer index 7eedae7..cf83ab5 100644 --- a/modules/scratch_buffer +++ b/modules/scratch_buffer @@ -14,6 +14,9 @@ c99 libc-config stdbool stddef +malloc-posix +realloc-posix +free-posix configure.ac: diff --git a/modules/simple-atomic b/modules/simple-atomic new file mode 100644 index 0000000..5f3f63d --- a/dev/null +++ b/modules/simple-atomic @@ -0,0 +1,25 @@ +Description: +Simple atomic operations for multithreading. + +Files: +lib/simple-atomic.h +lib/simple-atomic.c + +Depends-on: +stdint +sparcv8+ + +configure.ac: +AC_CHECK_HEADERS_ONCE([pthread.h]) + +Makefile.am: +lib_SOURCES += simple-atomic.c + +Include: +"simple-atomic.h" + +License: +LGPLv2+ + +Maintainer: +all diff --git a/modules/simple-atomic-tests b/modules/simple-atomic-tests new file mode 100644 index 0000000..a57b9fc --- a/dev/null +++ b/modules/simple-atomic-tests @@ -0,0 +1,14 @@ +Files: +tests/test-simple-atomic.c +tests/macros.h + +Depends-on: +thread +yield + +configure.ac: + +Makefile.am: +TESTS += test-simple-atomic +check_PROGRAMS += test-simple-atomic +test_simple_atomic_LDADD = $(LDADD) @LIBMULTITHREAD@ @YIELD_LIB@ diff --git a/modules/string-buffer b/modules/string-buffer new file mode 100644 index 0000000..54da1db --- a/dev/null +++ b/modules/string-buffer @@ -0,0 +1,26 @@ +Description: +A buffer that accumulates a string by piecewise concatenation. + +Files: +lib/string-buffer.h +lib/string-buffer.c + +Depends-on: +stdbool +attribute +stdarg +vsnprintf-posix + +configure.ac: + +Makefile.am: +lib_SOURCES += string-buffer.c + +Include: +"string-buffer.h" + +License: +LGPL + +Maintainer: +all diff --git a/modules/string-buffer-tests b/modules/string-buffer-tests new file mode 100644 index 0000000..38473fd --- a/dev/null +++ b/modules/string-buffer-tests @@ -0,0 +1,11 @@ +Files: +tests/test-string-buffer.c +tests/macros.h + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-string-buffer +check_PROGRAMS += test-string-buffer diff --git a/tests/test-asyncsafe-linked_list.c b/tests/test-asyncsafe-linked_list.c new file mode 100644 index 0000000..56e76bb --- a/dev/null +++ b/tests/test-asyncsafe-linked_list.c @@ -0,0 +1,322 @@ +/* Test of async-safe sequential list data type implementation. + Copyright (C) 2021 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#include <config.h> + +/* Work around GCC bug 44511. */ +#if 4 < __GNUC__ + (3 <= __GNUC_MINOR__) +# pragma GCC diagnostic ignored "-Wreturn-type" +#endif + +#include "gl_linked_list.h" + +#if SIGNAL_SAFE_LIST + +# if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS /* || USE_WINDOWS_THREADS */ +/* This test works only with POSIX compatible threads. + With Windows threads, send_signal() has to be implemented as + raise (SIGINT); + hence only test == 2 tests anything, and in fact only 5 signals arrive. + This small test is not able to detect a buggy implementation. Therefore + mark the test as skipped in this case. */ + +# include <signal.h> +# include <stdint.h> +# include <stdlib.h> +# include <unistd.h> +# include <time.h> + +# include "glthread/thread.h" +# include "glthread/yield.h" + +# include "macros.h" + +# define RANDOM(n) (rand () % (n)) +# define RANDOM_OBJECT() ((void *) (uintptr_t) RANDOM (10000)) + +/* test == 1: signals are executed in an idle thread. + test == 2: signals are executed in the signal-sending thread. + test == 3: signals are executed in the mutator thread. */ +static int volatile test; + +static uintptr_t volatile sum_before_current_operation; +static uintptr_t volatile sum_after_current_operation; + +static gl_list_t volatile list1; + +static gl_thread_t volatile signal_target; + +/* Statistics. */ +static unsigned int volatile num_mutations; +static unsigned int volatile num_signals_sent; +static unsigned int volatile num_signals_arrived; + +/* Blocks the SIGINT signal in the current thread. */ +static void +block_sigint (void) +{ + sigset_t mask; + + sigemptyset (&mask); + sigaddset (&mask, SIGINT); + sigprocmask (SIG_BLOCK, &mask, NULL); /* equivalent to pthread_sigmask */ +} + +/* This thread is idle. */ +static void * +idle_thread (void *arg) +{ + for (;;) + gl_thread_yield (); + + /*NOTREACHED*/ +} + +/* The signal handler iterates through the list and verifies that the sum of + all elements in the list is one of the two allowed values. */ +static _GL_ASYNC_SAFE void +sigint_handler (int signo) +{ + num_signals_arrived++; + + uintptr_t sum = 0; + { + gl_list_iterator_t iter = gl_list_iterator (list1); + const void *elt; + + while (gl_list_iterator_next (&iter, &elt, NULL)) + sum += (uintptr_t) elt; + gl_list_iterator_free (&iter); + } + if (!(sum == sum_before_current_operation + || sum == sum_after_current_operation)) + { + /* POSIX does not allow uses of stdio from within a signal handler, but + it should work here, because the rest of the program does not use + stdio. */ + fprintf (stderr, "sum = %lu, expected %lu or %lu\n", + (unsigned long) sum, + (unsigned long) sum_before_current_operation, + (unsigned long) sum_after_current_operation); + fflush (stderr); + abort (); + } +} + +/* Sends a SIGINT signal to the current process. */ +static void +send_signal (void) +{ +#if 0 + /* This does not work for test != 2, because raise() sends the signal to the + current thread always, and if test != 2 the signal is eternally blocked + in the current thread; thus it will never get delivered. */ + raise (SIGINT); +#else + /* This works: Either + kill (getpid (), SIGINT); + or + pthread_kill (signal_target, SIGINT); + The difference is that for kill(), the OS determines the (only) thread that + has not blocked the signal, whereas for pthread_kill() we have manually + determined this thread. */ + kill (getpid (), SIGINT); +#endif +} + +/* This thread permanently sends SIGINT signals. */ +static void * +signal_sending_thread (void *arg) +{ + if (test != 2) + block_sigint (); + + int repeat; + + for (repeat = 1000; repeat > 0; repeat--) + { + num_signals_sent++; send_signal (); + num_signals_sent++; send_signal (); + num_signals_sent++; send_signal (); + num_signals_sent++; send_signal (); + num_signals_sent++; send_signal (); + { + struct timespec ts; + ts.tv_sec = 0; ts.tv_nsec = 1000000; + nanosleep (&ts, NULL); + } + gl_thread_yield (); + } + + printf ("Sent %u signals. Received %u signals. Done after %u mutations.\n", + num_signals_sent, num_signals_arrived, num_mutations); + + exit (0); + + /*NOTREACHED*/ +} + +/* This thread repeatedly adds and removes objects from the list. */ +static void * +mutator_thread (void *arg) +{ + if (test != 3) + block_sigint (); + + gl_list_t list2 = (gl_list_t) arg; + + for (num_mutations = 0; ; num_mutations++) + { + unsigned int operation = RANDOM (2); + switch (operation) + { + case 0: /* Add an element. */ + { + const void *obj = RANDOM_OBJECT (); + ASSERT (gl_list_nx_add_first (list2, obj) != NULL); + sum_after_current_operation = + sum_before_current_operation + (uintptr_t) obj; + ASSERT (gl_list_nx_add_first (list1, obj) != NULL); + sum_before_current_operation = sum_after_current_operation; + } + break; + case 1: /* Remove an element. */ + if (gl_list_size (list2) > 0) + { + size_t index = RANDOM (gl_list_size (list2)); + const void *obj = gl_list_get_at (list2, index); + ASSERT (gl_list_remove (list2, obj)); + sum_after_current_operation = + sum_before_current_operation - (uintptr_t) obj; + ASSERT (gl_list_remove (list1, obj)); + sum_before_current_operation = sum_after_current_operation; + } + break; + } + } + + /*NOTREACHED*/ +} + +int +main (int argc, char *argv[]) +{ + test = atoi (argv[1]); + + /* Allow the user to provide a non-default random seed on the command line. */ + if (argc > 2) + srand (atoi (argv[2])); + + gl_list_t list2; + /* Initialize list1 and list2. */ + { + size_t initial_size = RANDOM (50); + const void **contents = + (const void **) malloc (initial_size * sizeof (const void *)); + size_t i; + + for (i = 0; i < initial_size; i++) + contents[i] = RANDOM_OBJECT (); + + list1 = gl_list_nx_create_empty (GL_LINKED_LIST, NULL, NULL, NULL, true); + ASSERT (list1 != NULL); + for (i = 0; i < initial_size; i++) + ASSERT (gl_list_nx_add_first (list1, contents[i]) != NULL); + + list2 = gl_list_nx_create_empty (GL_LINKED_LIST, NULL, NULL, NULL, true); + ASSERT (list2 != NULL); + for (i = 0; i < initial_size; i++) + ASSERT (gl_list_nx_add_last (list2, contents[i]) != NULL); + + uintptr_t initial_sum = 0; + for (i = 0; i < initial_size; i++) + initial_sum += (uintptr_t) contents[i]; + sum_before_current_operation = initial_sum; + sum_after_current_operation = initial_sum; + } + + /* Install the signal handler. + It needs to be done with sigaction(), not signal(), otherwise on Solaris + and AIX the program crashes at the second incoming SIGINT. */ + #if 0 + signal (SIGINT, sigint_handler); + #else + { + struct sigaction action; + action.sa_handler = sigint_handler; + action.sa_flags = SA_RESTART | SA_NODEFER; + sigemptyset (&action.sa_mask); + ASSERT (sigaction (SIGINT, &action, NULL) == 0); + } + #endif + + /* Launch the threads. */ + switch (test) + { + case 1: + { + signal_target = gl_thread_create (idle_thread, NULL); + gl_thread_create (mutator_thread, list2); + signal_sending_thread (NULL); + abort (); + } + + case 2: + { + gl_thread_create (mutator_thread, list2); + signal_target = gl_thread_self (); signal_sending_thread (NULL); + abort (); + } + + case 3: + { + signal_target = gl_thread_create (mutator_thread, list2); + signal_sending_thread (NULL); + abort (); + } + + default: + ASSERT (false); + } +} + +# else + +# include <stdio.h> + +int +main () +{ + fputs ("Skipping test: POSIX compatible multithreading not enabled\n", stderr); + return 77; +} + +# endif + +#else + +# include <stdio.h> + +int +main () +{ + fputs ("Skipping test: signal-safety of linked lists is not enabled\n", stderr); + return 77; +} + +#endif diff --git a/tests/test-asyncsafe-linked_list.sh b/tests/test-asyncsafe-linked_list.sh new file mode 100755 index 0000000..c2ad176 --- a/dev/null +++ b/tests/test-asyncsafe-linked_list.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +st=0 +for i in 1 2 3 ; do + ${CHECKER} ./test-asyncsafe-linked_list${EXEEXT} $i + result=$? + if test $result = 77; then + st=77 + break + fi + if test $result != 0; then + echo test-asyncsafe-linked_list.sh: test case $i failed >&2 + st=1 + fi +done +exit $st diff --git a/tests/test-c32isalnum.c b/tests/test-c32isalnum.c index 3720810..8f61ad9 100644 --- a/tests/test-c32isalnum.c +++ b/tests/test-c32isalnum.c @@ -149,7 +149,7 @@ main (int argc, char *argv[]) /* U+00D7 MULTIPLICATION SIGN */ is = for_character ("\241\337", 2); ASSERT (is == 0); - #if !(defined __APPLE__ && defined __MACH__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__) /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ is = for_character ("\217\251\254", 3); ASSERT (is != 0); @@ -165,7 +165,7 @@ main (int argc, char *argv[]) is = for_character ("\243\261", 2); ASSERT (is != 0); #endif - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ is = for_character ("\243\355", 2); ASSERT (is != 0); diff --git a/tests/test-c32isalpha.c b/tests/test-c32isalpha.c index 5be0178..9b07186 100644 --- a/tests/test-c32isalpha.c +++ b/tests/test-c32isalpha.c @@ -147,7 +147,7 @@ main (int argc, char *argv[]) /* U+00D7 MULTIPLICATION SIGN */ is = for_character ("\241\337", 2); ASSERT (is == 0); - #if !(defined __APPLE__ && defined __MACH__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__) /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ is = for_character ("\217\251\254", 3); ASSERT (is != 0); @@ -163,7 +163,7 @@ main (int argc, char *argv[]) is = for_character ("\243\261", 2); ASSERT (is == 0); #endif - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+FF4D FULLWIDTH LATIN SMALL LETTER M */ is = for_character ("\243\355", 2); ASSERT (is != 0); diff --git a/tests/test-c32isblank.c b/tests/test-c32isblank.c index 984d0d8..a615388 100644 --- a/tests/test-c32isblank.c +++ b/tests/test-c32isblank.c @@ -74,7 +74,7 @@ main (int argc, char *argv[]) switch (c) { case '\t': - #if !defined __NetBSD__ + #if !(defined __FreeBSD__ || defined __NetBSD__) case '\v': #endif case '\f': diff --git a/tests/test-c32islower.c b/tests/test-c32islower.c index 8bcffaf..0b811fd 100644 --- a/tests/test-c32islower.c +++ b/tests/test-c32islower.c @@ -156,12 +156,12 @@ main (int argc, char *argv[]) /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */ is = for_character ("\217\252\261", 3); ASSERT (is == 0); - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__ || defined __CYGWIN__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__ || defined __CYGWIN__) /* U+00DF LATIN SMALL LETTER SHARP S */ is = for_character ("\217\251\316", 3); ASSERT (is != 0); #endif - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */ is = for_character ("\217\253\261", 3); ASSERT (is != 0); @@ -172,7 +172,7 @@ main (int argc, char *argv[]) /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */ is = for_character ("\217\251\250", 3); ASSERT (is == 0); - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+0142 LATIN SMALL LETTER L WITH STROKE */ is = for_character ("\217\251\310", 3); ASSERT (is != 0); @@ -269,7 +269,7 @@ main (int argc, char *argv[]) /* U+00B2 SUPERSCRIPT TWO */ is = for_character ("\201\060\205\065", 4); ASSERT (is == 0); - #if !(defined __GLIBC__ || (defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !(defined __GLIBC__ || (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+00B5 MICRO SIGN */ is = for_character ("\201\060\205\070", 4); ASSERT (is == 0); diff --git a/tests/test-c32isupper.c b/tests/test-c32isupper.c index 05b969d..5604a8f 100644 --- a/tests/test-c32isupper.c +++ b/tests/test-c32isupper.c @@ -151,7 +151,7 @@ main (int argc, char *argv[]) case '2': /* Locale encoding is EUC-JP. */ { - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */ is = for_character ("\217\252\261", 3); ASSERT (is != 0); @@ -165,7 +165,7 @@ main (int argc, char *argv[]) /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */ is = for_character ("\217\253\363", 3); ASSERT (is == 0); - #if !((defined __APPLE__ && defined __MACH__) || defined __NetBSD__) + #if !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__) /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */ is = for_character ("\217\251\250", 3); ASSERT (is != 0); diff --git a/tests/test-immutable.c b/tests/test-immutable.c index 4bee1f2..18ccf9d 100644 --- a/tests/test-immutable.c +++ b/tests/test-immutable.c @@ -45,7 +45,7 @@ static void install_segv_handler (void) { signal (SIGSEGV, segv_handler); -# if defined __APPLE__ && defined __MACH__ +# if (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ signal (SIGBUS, segv_handler); # endif } diff --git a/tests/test-posix_spawn_file_actions_addclose.c b/tests/test-posix_spawn_file_actions_addclose.c index 3aca333..2c910ea 100644 --- a/tests/test-posix_spawn_file_actions_addclose.c +++ b/tests/test-posix_spawn_file_actions_addclose.c @@ -54,6 +54,8 @@ main (void) errno = 0; ASSERT (posix_spawn_file_actions_addclose (&actions, -1) == EBADF); } + /* This behaviour is not mandated by POSIX, but happens to pass on all + platforms. */ { int bad_fd = big_fd (); errno = 0; diff --git a/tests/test-posixtm.c b/tests/test-posixtm.c index ea20564..b07e0c5 100644 --- a/tests/test-posixtm.c +++ b/tests/test-posixtm.c @@ -178,7 +178,7 @@ main (void) if (t_out != t_exp) { printf ("%s mismatch (-: actual; +:expected)\n-%12ld\n+%12ld\n", - T[i].in, t_out, t_exp); + T[i].in, (long) t_out, (long) t_exp); fail = 1; } } diff --git a/tests/test-regex.c b/tests/test-regex.c index 4a4ff39..adccf21 100644 --- a/tests/test-regex.c +++ b/tests/test-regex.c @@ -55,6 +55,111 @@ really_utf8 (void) return strcmp (locale_charset (), "UTF-8") == 0; } +/* Tests supposed to match; copied from glibc posix/bug-regex11.c. */ +static struct +{ + const char *pattern; + const char *string; + int flags, nmatch; + regmatch_t rm[5]; +} const tests[] = { + /* Test for newline handling in regex. */ + { "[^~]*~", "\nx~y", 0, 2, { { 0, 3 }, { -1, -1 } } }, + /* Other tests. */ + { "a(.*)b", "a b", REG_EXTENDED, 2, { { 0, 3 }, { 1, 2 } } }, + { ".*|\\([KIO]\\)\\([^|]*\\).*|?[KIO]", "10~.~|P|K0|I10|O16|?KSb", 0, 3, + { { 0, 21 }, { 15, 16 }, { 16, 18 } } }, + { ".*|\\([KIO]\\)\\([^|]*\\).*|?\\1", "10~.~|P|K0|I10|O16|?KSb", 0, 3, + { { 0, 21 }, { 8, 9 }, { 9, 10 } } }, + { "^\\(a*\\)\\1\\{9\\}\\(a\\{0,9\\}\\)\\([0-9]*;.*[^a]\\2\\([0-9]\\)\\)", + "a1;;0a1aa2aaa3aaaa4aaaaa5aaaaaa6aaaaaaa7aaaaaaaa8aaaaaaaaa9aa2aa1a0", 0, + 5, { { 0, 67 }, { 0, 0 }, { 0, 1 }, { 1, 67 }, { 66, 67 } } }, + /* Test for BRE expression anchoring. POSIX says just that this may match; + in glibc regex it always matched, so avoid changing it. */ + { "\\(^\\|foo\\)bar", "bar", 0, 2, { { 0, 3 }, { -1, -1 } } }, + { "\\(foo\\|^\\)bar", "bar", 0, 2, { { 0, 3 }, { -1, -1 } } }, + /* In ERE this must be treated as an anchor. */ + { "(^|foo)bar", "bar", REG_EXTENDED, 2, { { 0, 3 }, { -1, -1 } } }, + { "(foo|^)bar", "bar", REG_EXTENDED, 2, { { 0, 3 }, { -1, -1 } } }, + /* Here ^ cannot be treated as an anchor according to POSIX. */ + { "(^|foo)bar", "(^|foo)bar", 0, 2, { { 0, 10 }, { -1, -1 } } }, + { "(foo|^)bar", "(foo|^)bar", 0, 2, { { 0, 10 }, { -1, -1 } } }, + /* More tests on backreferences. */ + { "()\\1", "x", REG_EXTENDED, 2, { { 0, 0 }, { 0, 0 } } }, + { "()x\\1", "x", REG_EXTENDED, 2, { { 0, 1 }, { 0, 0 } } }, + { "()\\1*\\1*", "", REG_EXTENDED, 2, { { 0, 0 }, { 0, 0 } } }, + { "([0-9]).*\\1(a*)", "7;7a6", REG_EXTENDED, 3, { { 0, 4 }, { 0, 1 }, { 3, 4 } } }, + { "([0-9]).*\\1(a*)", "7;7a", REG_EXTENDED, 3, { { 0, 4 }, { 0, 1 }, { 3, 4 } } }, + { "(b)()c\\1", "bcb", REG_EXTENDED, 3, { { 0, 3 }, { 0, 1 }, { 1, 1 } } }, + { "()(b)c\\2", "bcb", REG_EXTENDED, 3, { { 0, 3 }, { 0, 0 }, { 0, 1 } } }, + { "a(b)()c\\1", "abcb", REG_EXTENDED, 3, { { 0, 4 }, { 1, 2 }, { 2, 2 } } }, + { "a()(b)c\\2", "abcb", REG_EXTENDED, 3, { { 0, 4 }, { 1, 1 }, { 1, 2 } } }, + { "()(b)\\1c\\2", "bcb", REG_EXTENDED, 3, { { 0, 3 }, { 0, 0 }, { 0, 1 } } }, + { "(b())\\2\\1", "bbbb", REG_EXTENDED, 3, { { 0, 2 }, { 0, 1 }, { 1, 1 } } }, + { "a()(b)\\1c\\2", "abcb", REG_EXTENDED, 3, { { 0, 4 }, { 1, 1 }, { 1, 2 } } }, + { "a()d(b)\\1c\\2", "adbcb", REG_EXTENDED, 3, { { 0, 5 }, { 1, 1 }, { 2, 3 } } }, + { "a(b())\\2\\1", "abbbb", REG_EXTENDED, 3, { { 0, 3 }, { 1, 2 }, { 2, 2 } } }, + { "(bb())\\2\\1", "bbbb", REG_EXTENDED, 3, { { 0, 4 }, { 0, 2 }, { 2, 2 } } }, + { "^([^,]*),\\1,\\1$", "a,a,a", REG_EXTENDED, 2, { { 0, 5 }, { 0, 1 } } }, + { "^([^,]*),\\1,\\1$", "ab,ab,ab", REG_EXTENDED, 2, { { 0, 8 }, { 0, 2 } } }, + { "^([^,]*),\\1,\\1,\\1$", "abc,abc,abc,abc", REG_EXTENDED, 2, + { { 0, 15 }, { 0, 3 } } }, + { "^(.?)(.?)(.?)(.?)(.?).?\\5\\4\\3\\2\\1$", + "level", REG_NOSUB | REG_EXTENDED, 0, { { -1, -1 } } }, + { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$|^.?$", + "level", REG_NOSUB | REG_EXTENDED, 0, { { -1, -1 } } }, + { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$|^.?$", + "abcdedcba", REG_EXTENDED, 1, { { 0, 9 } } }, + /* XXX Not used since they fail so far. */ + { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$|^.?$", + "ababababa", REG_EXTENDED, 1, { { 0, 9 } } }, + { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$", + "level", REG_NOSUB | REG_EXTENDED, 0, { { -1, -1 } } }, + { "^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$", + "ababababa", REG_EXTENDED, 1, { { 0, 9 } } }, +}; + +static void +bug_regex11 (void) +{ + regex_t re; + regmatch_t rm[5]; + size_t i; + int n; + + for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i) + { + n = regcomp (&re, tests[i].pattern, tests[i].flags); + if (n != 0) + { + char buf[500]; + regerror (n, &re, buf, sizeof (buf)); + report_error ("%s: regcomp %zd failed: %s", tests[i].pattern, i, buf); + continue; + } + + if (regexec (&re, tests[i].string, tests[i].nmatch, rm, 0)) + { + report_error ("%s: regexec %zd failed", tests[i].pattern, i); + regfree (&re); + continue; + } + + for (n = 0; n < tests[i].nmatch; ++n) + if (rm[n].rm_so != tests[i].rm[n].rm_so + || rm[n].rm_eo != tests[i].rm[n].rm_eo) + { + if (tests[i].rm[n].rm_so == -1 && tests[i].rm[n].rm_eo == -1) + break; + report_error ("%s: regexec %zd match failure rm[%d] %d..%d", + tests[i].pattern, i, n, rm[n].rm_so, rm[n].rm_eo); + break; + } + + regfree (&re); + } +} + int main (void) { @@ -65,11 +170,15 @@ main (void) struct re_registers regs; #if HAVE_DECL_ALARM - /* Some builds of glibc go into an infinite loop on this test. */ - int alarm_value = 2; + /* In case a bug causes glibc to go into an infinite loop. + The tests should take less than 10 s on a reasonably modern CPU. */ + int alarm_value = 1000; signal (SIGALRM, SIG_DFL); alarm (alarm_value); #endif + + bug_regex11 (); + if (setlocale (LC_ALL, "en_US.UTF-8")) { { @@ -290,13 +399,43 @@ main (void) { memset (®s, 0, sizeof regs); static char const data[] = "WXY"; - if (re_search (®ex, data, sizeof data - 1, 0, 3, ®s) < 0) + i = re_search (®ex, data, sizeof data - 1, 0, 3, ®s); + if (i < 0) report_error ("re_search '%s' on '%s' returned %d", pat_x, data, i); regfree (®ex); free (regs.start); free (regs.end); } + /* glibc bug 11053. */ + re_set_syntax (RE_SYNTAX_POSIX_BASIC); + memset (®ex, 0, sizeof regex); + static char const pat_sub2[] = "\\(a*\\)*a*\\1"; + s = re_compile_pattern (pat_sub2, sizeof pat_sub2 - 1, ®ex); + if (s) + report_error ("%s: %s", pat_sub2, s); + else + { + memset (®s, 0, sizeof regs); + static char const data[] = "a"; + int datalen = sizeof data - 1; + i = re_search (®ex, data, datalen, 0, datalen, ®s); + if (i != 0) + report_error ("re_search '%s' on '%s' returned %d", pat_sub2, data, i); + else if (regs.num_regs < 2) + report_error ("re_search '%s' on '%s' returned only %d registers", + pat_sub2, data, (int) regs.num_regs); + else if (! (regs.start[0] == 0 && regs.end[0] == 1)) + report_error ("re_search '%s' on '%s' returned wrong match [%d,%d)", + pat_sub2, data, (int) regs.start[0], (int) regs.end[0]); + else if (! (regs.start[1] == 0 && regs.end[1] == 0)) + report_error ("re_search '%s' on '%s' returned wrong submatch [%d,%d)", + pat_sub2, data, regs.start[1], regs.end[1]); + regfree (®ex); + free (regs.start); + free (regs.end); + } + /* Catch a bug reported by Vin Shelton in https://lists.gnu.org/r/bug-coreutils/2007-06/msg00089.html */ diff --git a/tests/test-simple-atomic.c b/tests/test-simple-atomic.c new file mode 100644 index 0000000..04baf05 --- a/dev/null +++ b/tests/test-simple-atomic.c @@ -0,0 +1,234 @@ +/* Test of simple atomic operations for multithreading. + Copyright (C) 2021 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#include <config.h> + +#include "simple-atomic.h" + +#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS + +/* Whether to help the scheduler through explicit yield(). + Uncomment this to see if the operating system has a fair scheduler. */ +#define EXPLICIT_YIELD 1 + +/* Number of simultaneous threads. */ +#define THREAD_COUNT 4 + +/* Number of operations performed in each thread. + With a smaller count, say 100, we often get an "OK" result even with the racy + implementation. */ +#define REPEAT_COUNT 1000 + +#if EXPLICIT_YIELD +# define yield() gl_thread_yield () +#else +# define yield() +#endif + +#include "glthread/thread.h" +#include "glthread/yield.h" + +#include "macros.h" + +/* Counters for each thread. */ +static unsigned int counter[THREAD_COUNT][5]; + +/* A variable of type 'unsigned int'. */ +static unsigned int int_variable; + +static void * +int_mutator_thread (void *arg) +{ + int *pcounter = (int *) arg; + int repeat; + + for (repeat = REPEAT_COUNT; repeat > 0; repeat--) + { + if (atomic_compare_and_swap (&int_variable, 0, 10) == 0) + pcounter[0]++; + yield (); + + if (atomic_compare_and_swap (&int_variable, 14, 17) == 14) + pcounter[1]++; + yield (); + + if (atomic_compare_and_swap (&int_variable, 20, 0) == 20) + pcounter[2]++; + yield (); + + if (atomic_compare_and_swap (&int_variable, 10, 14) == 10) + pcounter[3]++; + yield (); + + if (atomic_compare_and_swap (&int_variable, 17, 20) == 17) + pcounter[4]++; + yield (); + } + + return NULL; +} + +/* A variable of type 'uintptr_t'. */ +static uintptr_t ptr_variable; + +static void * +ptr_mutator_thread (void *arg) +{ + int *pcounter = (int *) arg; + int repeat; + + for (repeat = REPEAT_COUNT; repeat > 0; repeat--) + { + if (atomic_compare_and_swap_ptr (&ptr_variable, 0, 10) == 0) + pcounter[0]++; + yield (); + + if (atomic_compare_and_swap_ptr (&ptr_variable, 14, 17) == 14) + pcounter[1]++; + yield (); + + if (atomic_compare_and_swap_ptr (&ptr_variable, 20, 0) == 20) + pcounter[2]++; + yield (); + + if (atomic_compare_and_swap_ptr (&ptr_variable, 10, 14) == 10) + pcounter[3]++; + yield (); + + if (atomic_compare_and_swap_ptr (&ptr_variable, 17, 20) == 17) + pcounter[4]++; + yield (); + } + + return NULL; +} + +int +main () +{ + /* Check simple uses of atomic_compare_and_swap. */ + { + unsigned int x[3] = { 0xDEADBEEFU, 11, 0xDEADBEEFU }; + + ASSERT (atomic_compare_and_swap (&x[1], 0, 17) == 11); + ASSERT (x[1] == 11); + + ASSERT (atomic_compare_and_swap (&x[1], 4, 11) == 11); + ASSERT (x[1] == 11); + + ASSERT (atomic_compare_and_swap (&x[1], 11, 15) == 11); + ASSERT (x[1] == 15); + + ASSERT (x[0] == 0xDEADBEEFU); + ASSERT (x[2] == 0xDEADBEEFU); + } + + /* Check simple uses of atomic_compare_and_swap_ptr. */ + { + uintptr_t v1 = ~(uintptr_t)0 / 3; + uintptr_t v2 = ~(uintptr_t)0 / 5 * 4; + uintptr_t v3 = ~(uintptr_t)0 / 7 * 3; + uintptr_t x[3] = { 0xDEADBEEFU, v1, 0xDEADBEEFU }; + + ASSERT (atomic_compare_and_swap_ptr (&x[1], 0, v3) == v1); + ASSERT (x[1] == v1); + + ASSERT (atomic_compare_and_swap_ptr (&x[1], 4, v1) == v1); + ASSERT (x[1] == v1); + + ASSERT (atomic_compare_and_swap_ptr (&x[1], v1, v2) == v1); + ASSERT (x[1] == v2); + + ASSERT (x[0] == 0xDEADBEEFU); + ASSERT (x[2] == 0xDEADBEEFU); + } + + /* Check atomicity of atomic_compare_and_swap. */ + { + void * (*funcs[2]) (void *) = { int_mutator_thread, ptr_mutator_thread }; + int f; + for (f = 0; f < 2; f++) + { + void * (*func) (void *) = funcs[f]; + int i, j; + gl_thread_t threads[THREAD_COUNT]; + + /* Initialization. */ + for (i = 0; i < THREAD_COUNT; i++) + for (j = 0; j < 5; j++) + counter[i][j] = 0; + + /* Spawn the threads. */ + for (i = 0; i < THREAD_COUNT; i++) + threads[i] = gl_thread_create (func, &counter[i][0]); + + /* Wait for the threads to terminate. */ + for (i = 0; i < THREAD_COUNT; i++) + gl_thread_join (threads[i], NULL); + + /* Sum up the work that the threads have done. */ + unsigned int sum[5]; + for (j = 0; j < 5; j++) + { + sum[j] = 0; + for (i = 0; i < THREAD_COUNT; i++) + sum[j] += counter[i][j]; + } + + /* If things went atomically, the threads have moved the variable's + value through the cycle 0 -> 10 -> 14 -> 17 -> 20 -> 0 ... a large + number of times. + sum[0] is the number of transitions 0 -> 10. + sum[3] is the number of transitions 10 -> 14. + sum[1] is the number of transitions 14 -> 17. + sum[4] is the number of transitions 17 -> 20. + sum[2] is the number of transitions 20 -> 0. + Since the cycle started at 0 and ends anywhere (namely, when all + threads when through their loop REPEAT_COUNT times), the sequence + sum[0], sum[3], sum[1], sum[4], sum[2], sum[0] - 1 + must be monotonically decreasing. + + If things did not go atomically, the counters don't exhibit this + pattern. */ + printf ("Counters: %u %u %u %u %u\n", + sum[0], sum[3], sum[1], sum[4], sum[2]); + ASSERT ((sum[0] == sum[3] || sum[0] == sum[3] + 1) + && (sum[3] == sum[1] || sum[3] == sum[1] + 1) + && (sum[1] == sum[4] || sum[1] == sum[4] + 1) + && (sum[4] == sum[2] || sum[4] == sum[2] + 1) + && (sum[2] + 1 == sum[0] || sum[2] == sum[0])); + } + } + + return 0; +} + +#else + +/* No multithreading available. */ + +#include <stdio.h> + +int +main () +{ + fputs ("Skipping test: multithreading not enabled\n", stderr); + return 77; +} + +#endif diff --git a/tests/test-string-buffer.c b/tests/test-string-buffer.c new file mode 100644 index 0000000..ecf5160 --- a/dev/null +++ b/tests/test-string-buffer.c @@ -0,0 +1,115 @@ +/* Test of buffer that accumulates a string by piecewise concatenation. + Copyright (C) 2021 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 2, 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 Bruno Haible <bruno@clisp.org>, 2021. */ + +#include <config.h> + +#include "string-buffer.h" + +#include <string.h> + +#include "macros.h" + +static int +my_appendf (struct string_buffer *buffer, const char *formatstring, ...) +{ + va_list args; + + va_start (args, formatstring); + int ret = sb_appendvf (buffer, formatstring, args); + va_end (args); + + return ret; +} + +char invalid_format_string_1[] = "%&"; +char invalid_format_string_2[] = "%^"; + +int +main () +{ + /* Test simple string concatenation. */ + { + struct string_buffer buffer; + + sb_init (&buffer); + char *s = sb_dupfree (&buffer); + ASSERT (s != NULL && strcmp (s, "") == 0); + free (s); + } + + { + struct string_buffer buffer; + + sb_init (&buffer); + sb_append (&buffer, "abc"); + sb_append (&buffer, ""); + sb_append (&buffer, "defg"); + char *s = sb_dupfree (&buffer); + ASSERT (s != NULL && strcmp (s, "abcdefg") == 0); + free (s); + } + + /* Test printf-like formatting. */ + { + struct string_buffer buffer; + + sb_init (&buffer); + sb_append (&buffer, "<"); + sb_appendf (&buffer, "%x", 3735928559U); + sb_append (&buffer, ">"); + char *s = sb_dupfree (&buffer); + ASSERT (s != NULL && strcmp (s, "<deadbeef>") == 0); + free (s); + } + + /* Test vprintf-like formatting. */ + { + struct string_buffer buffer; + + sb_init (&buffer); + sb_append (&buffer, "<"); + my_appendf (&buffer, "%x", 3735928559U); + sb_append (&buffer, ">"); + char *s = sb_dupfree (&buffer); + ASSERT (s != NULL && strcmp (s, "<deadbeef>") == 0); + free (s); + } + + /* Test printf-like formatting failure. + On all systems except AIX, trying to convert the wide-character 0x76543210 + to a multibyte string (in the "C" locale) fails. + On all systems where REPLACE_VSNPRINTF=1 (this includes AIX), i.e. where + the Gnulib implementation of vsnprintf() is used), invalid format + directives make the *printf call fail. */ + { + struct string_buffer buffer; + + sb_init (&buffer); + sb_append (&buffer, "<"); + sb_appendf (&buffer, "%lc", 0x76543210); + sb_append (&buffer, "|"); + sb_appendf (&buffer, invalid_format_string_1, 1); + sb_append (&buffer, "|"); + sb_appendf (&buffer, invalid_format_string_2, 2); + sb_append (&buffer, ">"); + char *s = sb_dupfree (&buffer); + ASSERT (s == NULL); + } + + return 0; +} diff --git a/top/maint.mk b/top/maint.mk index 934f23d..ae3a817 100644 --- a/top/maint.mk +++ b/top/maint.mk @@ -64,7 +64,11 @@ VC_LIST = $(srcdir)/$(_build-aux)/vc-list-files -C $(srcdir) # You can override this variable in cfg.mk if your gnulib submodule lives # in a different location. -gnulib_dir ?= $(srcdir)/gnulib +gnulib_dir ?= $(shell if test -d $(srcdir)/gnulib; then \ + echo $(srcdir)/gnulib; \ + else \ + echo ${GNULIB_SRCDIR}; \ + fi) # You can override this variable in cfg.mk to set your own regexp # matching files to ignore. |