On CheriBSD, I see these test failures: FAIL: test-pthread-tss FAIL: test-thread_local FAIL: test-tls FAIL: test-tss
In the debugger I see this: (gdb) where #0 random_r (estate=0x42319000 [rwRW,0x42319000-0x423190d0]) at /local/scratch/jenkins/workspace/CheriBSD-pipeline_releng_22.12@2/cheribsd/lib/libc/stdlib/random.c:471 #1 0x0000000040394578 in rand () at /local/scratch/jenkins/workspace/CheriBSD-pipeline_releng_22.12@2/cheribsd/lib/libc/stdlib/rand.c:85 #2 0x0000000000111468 in perhaps_yield () at ../../gltests/test-thread_local.c:79 #3 0x00000000001113dc in worker_thread (arg=0x8) at ../../gltests/test-thread_local.c:127 #4 0x00000000401a19d4 in thrd_entry (arg=<optimized out>) at /local/scratch/jenkins/workspace/CheriBSD-pipeline_releng_22.12@2/cheribsd/lib/libstdthreads/thrd.c:52 #5 0x00000000401e3de4 in thread_start (curthread=0x408f4a00 [rwRW,0x408f4a00-0x408f53d0]) at /local/scratch/jenkins/workspace/CheriBSD-pipeline_releng_22.12@2/cheribsd/lib/libthr/thread/thr_create.c:319 #6 0x00000000401e38ec in _pthread_create (thread=0xfffffff7fe90 [rwRW,0xfffffff7fe10-0xfffffff7ff10], attr=<optimized out>, start_routine=<optimized out>, arg=<optimized out>) at /local/scratch/jenkins/workspace/CheriBSD-pipeline_releng_22.12@2/cheribsd/lib/libthr/thread/thr_create.c:214 (gdb) info locals r = 0x423190d0 [rwRW,0x42319000-0x423190d0] f = 0x42319054 [rwRW,0x42319000-0x423190d0] i = <optimized out> So, rand() is crashing in multithreaded tests. But it works fine in the many single-threaded test programs. Could it be that rand() is not multithread- safe? According to the standards, rand() should be multithread-safe. When I add a 'rand' module and force it to invoke the gnulib implementation of random_r (via random()), I see a crash inside gnulib's random_r instead. But wait! That's because gnulib's 'random' implementation is also not multithread-safe: #ifdef _LIBC # include <libc-lock.h> #else /* Allow memory races; that's random enough. */ # define __libc_lock_define_initialized(class, name) # define __libc_lock_lock(name) ((void) 0) # define __libc_lock_unlock(name) ((void) 0) #endif Memory races are not "random"; they are undefined behaviour. They crash on CheriBSD and they may crash (or return low-quality random numbers) on other systems as well. With the patches below, rand() becomes multithread-safe, and the 4 test failures disappear. 2023-11-09 Bruno Haible <br...@clisp.org> rand: Add tests. * tests/test-rand.c: New file. * modules/rand-tests: New file. rand: New module. * lib/rand.c: New file, based on glibc/stdlib/rand.c. * m4/rand.m4: New file. * modules/rand: New file. * doc/posix-functions/rand.texi: Mention the new module. 2023-11-09 Bruno Haible <br...@clisp.org> random: Fix multithread-safety bug on CheriBSD. * m4/random.m4 (gl_FUNC_RANDOM): Override on CheriBSD. * lib/random.c: Include glthread/lock.h. (__libc_lock_define_initialized, __libc_lock_lock, __libc_lock_unlock): Define to do real locking. * modules/random (Depends-on): Add lock. * doc/posix-functions/random.texi: Mention the multithread-safety problem.
>From 0ab4517a51b70490b833ed099bfffe528c329503 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Thu, 9 Nov 2023 15:56:32 +0100 Subject: [PATCH 1/3] random: Fix multithread-safety bug on CheriBSD. * m4/random.m4 (gl_FUNC_RANDOM): Override on CheriBSD. * lib/random.c: Include glthread/lock.h. (__libc_lock_define_initialized, __libc_lock_lock, __libc_lock_unlock): Define to do real locking. * modules/random (Depends-on): Add lock. * doc/posix-functions/random.texi: Mention the multithread-safety problem. --- ChangeLog | 11 +++++++++++ doc/posix-functions/random.texi | 3 ++- lib/random.c | 8 ++++---- m4/random.m4 | 8 ++++++-- modules/random | 3 ++- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 51ba73819b..35a043ce7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2023-11-09 Bruno Haible <br...@clisp.org> + + random: Fix multithread-safety bug on CheriBSD. + * m4/random.m4 (gl_FUNC_RANDOM): Override on CheriBSD. + * lib/random.c: Include glthread/lock.h. + (__libc_lock_define_initialized, __libc_lock_lock, __libc_lock_unlock): + Define to do real locking. + * modules/random (Depends-on): Add lock. + * doc/posix-functions/random.texi: Mention the multithread-safety + problem. + 2023-11-09 Bruno Haible <br...@clisp.org> host-cpu-c-abi: Port to CHERI. diff --git a/doc/posix-functions/random.texi b/doc/posix-functions/random.texi index 19349617be..e0bb8e76bc 100644 --- a/doc/posix-functions/random.texi +++ b/doc/posix-functions/random.texi @@ -15,7 +15,8 @@ This function is only defined as an inline function on some platforms: Android 4.4. @item - +This function crashes when used in multithreaded programs on some platforms: +CheriBSD. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/random.c b/lib/random.c index 50080ef2d5..ac5999101a 100644 --- a/lib/random.c +++ b/lib/random.c @@ -67,10 +67,10 @@ #ifdef _LIBC # include <libc-lock.h> #else -/* Allow memory races; that's random enough. */ -# define __libc_lock_define_initialized(class, name) -# define __libc_lock_lock(name) ((void) 0) -# define __libc_lock_unlock(name) ((void) 0) +# include "glthread/lock.h" +# define __libc_lock_define_initialized gl_lock_define_initialized +# define __libc_lock_lock gl_lock_lock +# define __libc_lock_unlock gl_lock_unlock #endif /* An improved random number generation package. In addition to the standard diff --git a/m4/random.m4 b/m4/random.m4 index b0d1cb86ee..69bac2459a 100644 --- a/m4/random.m4 +++ b/m4/random.m4 @@ -1,4 +1,4 @@ -# random.m4 serial 6 +# random.m4 serial 7 dnl Copyright (C) 2012-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -7,6 +7,7 @@ AC_DEFUN([gl_FUNC_RANDOM], [ AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl We can't use AC_CHECK_FUNC here, because random() is defined as a dnl static inline function when compiling for Android 4.4 or older. @@ -43,7 +44,10 @@ AC_DEFUN([gl_FUNC_RANDOM] future*) REPLACE_SETSTATE=1 ;; esac fi - if test $ac_cv_func_initstate = no || test $ac_cv_func_setstate = no; then + dnl On CheriBSD, random() lacks locking, leading to an out-of-bounds read + dnl inside random_r. + if test $ac_cv_func_initstate = no || test $ac_cv_func_setstate = no \ + || case "$host" in aarch64c-*-freebsd*) true;; *) false;; esac; then dnl In order to define initstate or setstate, we need to define all the dnl functions at once. REPLACE_RANDOM=1 diff --git a/modules/random b/modules/random index a6ccbb777d..9774088bda 100644 --- a/modules/random +++ b/modules/random @@ -6,8 +6,9 @@ lib/random.c m4/random.m4 Depends-on: -libc-config [test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1] stdlib +libc-config [test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1] +lock [test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1] stdint [test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1] random_r [test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1] -- 2.34.1
>From 9d7322634e8e64aed2d53a67ab221b16f83aaabd Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Thu, 9 Nov 2023 16:00:28 +0100 Subject: [PATCH 2/3] rand: New module. * lib/rand.c: New file, based on glibc/stdlib/rand.c. * m4/rand.m4: New file. * modules/rand: New file. * doc/posix-functions/rand.texi: Mention the new module. --- ChangeLog | 8 ++++++++ doc/posix-functions/rand.texi | 5 ++++- lib/rand.c | 30 ++++++++++++++++++++++++++++++ m4/rand.m4 | 17 +++++++++++++++++ modules/rand | 29 +++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 lib/rand.c create mode 100644 m4/rand.m4 create mode 100644 modules/rand diff --git a/ChangeLog b/ChangeLog index 35a043ce7d..a6e6a8045a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2023-11-09 Bruno Haible <br...@clisp.org> + + rand: New module. + * lib/rand.c: New file, based on glibc/stdlib/rand.c. + * m4/rand.m4: New file. + * modules/rand: New file. + * doc/posix-functions/rand.texi: Mention the new module. + 2023-11-09 Bruno Haible <br...@clisp.org> random: Fix multithread-safety bug on CheriBSD. diff --git a/doc/posix-functions/rand.texi b/doc/posix-functions/rand.texi index 3d23c8d609..2f36a548a7 100644 --- a/doc/posix-functions/rand.texi +++ b/doc/posix-functions/rand.texi @@ -4,10 +4,13 @@ POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/rand.html} -Gnulib module: --- +Gnulib module: rand Portability problems fixed by Gnulib: @itemize +@item +This function crashes when used in multithreaded programs on some platforms: +CheriBSD. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/rand.c b/lib/rand.c new file mode 100644 index 0000000000..86f76cb422 --- /dev/null +++ b/lib/rand.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2023 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <stdlib.h> + +#ifndef _LIBC +# define __random random +#endif + +/* Return a random integer between 0 and RAND_MAX. */ +int +rand (void) +{ + return (int) __random (); +} diff --git a/m4/rand.m4 b/m4/rand.m4 new file mode 100644 index 0000000000..50b7fa3333 --- /dev/null +++ b/m4/rand.m4 @@ -0,0 +1,17 @@ +# rand.m4 serial 1 +dnl Copyright (C) 2023 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_RAND], +[ + AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) + + dnl On CheriBSD, rand() lacks locking, leading to an out-of-bounds read + dnl inside random_r. + case "$host" in + aarch64c-*-freebsd*) REPLACE_RAND=1 ;; + esac +]) diff --git a/modules/rand b/modules/rand new file mode 100644 index 0000000000..7cd6ca71c6 --- /dev/null +++ b/modules/rand @@ -0,0 +1,29 @@ +Description: +global random number generator + +Files: +lib/rand.c +m4/rand.m4 + +Depends-on: +stdlib +random [test $REPLACE_RAND = 1] + +configure.ac: +gl_FUNC_RAND +gl_CONDITIONAL([GL_COND_OBJ_RAND], [test $REPLACE_RAND = 1]) +gl_STDLIB_MODULE_INDICATOR([rand]) + +Makefile.am: +if GL_COND_OBJ_RAND +lib_SOURCES += rand.c +endif + +Include: +<stdlib.h> + +License: +LGPL + +Maintainer: +glibc -- 2.34.1
>From 23f0e4f7cdc5a03f44d7b204b7c78d51edc67eb7 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Thu, 9 Nov 2023 16:01:46 +0100 Subject: [PATCH 3/3] rand: Add tests. * tests/test-rand.c: New file. * modules/rand-tests: New file. --- ChangeLog | 4 ++++ modules/rand-tests | 11 +++++++++++ tests/test-rand.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 modules/rand-tests create mode 100644 tests/test-rand.c diff --git a/ChangeLog b/ChangeLog index a6e6a8045a..0c49471d04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2023-11-09 Bruno Haible <br...@clisp.org> + rand: Add tests. + * tests/test-rand.c: New file. + * modules/rand-tests: New file. + rand: New module. * lib/rand.c: New file, based on glibc/stdlib/rand.c. * m4/rand.m4: New file. diff --git a/modules/rand-tests b/modules/rand-tests new file mode 100644 index 0000000000..0a2cb7e714 --- /dev/null +++ b/modules/rand-tests @@ -0,0 +1,11 @@ +Files: +tests/test-rand.c +tests/signature.h + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-rand +check_PROGRAMS += test-rand diff --git a/tests/test-rand.c b/tests/test-rand.c new file mode 100644 index 0000000000..eae68be611 --- /dev/null +++ b/tests/test-rand.c @@ -0,0 +1,33 @@ +/* Test rand. + Copyright (C) 2023 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/>. */ + +#include <config.h> + +/* Specification. */ +#include <stdlib.h> + +#include "signature.h" +SIGNATURE_CHECK (rand, int, (void)); + +int +main () +{ + rand (); + rand (); + rand (); + + return 0; +} -- 2.34.1