Now that we have a <sys/random.h> module with test cases, we see that there is a conflict with the function defined on Solaris 11.3 and newer:
../gllib/sys/random.h: In member function ‘gnulib::_gl_getrandom_wrapper::operator gnulib::_gl_getrandom_wrapper::type() const’: ../gllib/sys/random.h:535:1: error: invalid conversion from ‘int (*)(void*, std::size_t, uint_t) {aka int (*)(void*, long unsigned int, unsigned int)}’ to ‘gnulib::_gl_getrandom_wrapper::type {aka long int (*)(void*, long unsigned int, unsigned int)}’ [-fpermissive] _GL_CXXALIAS_SYS (getrandom, ssize_t, ^ See https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html Thus, we need to override the function if it has a different return type. 2020-05-30 Bruno Haible <br...@clisp.org> getrandom: Override incompatible system function on Solaris 11. * lib/sys_random.in.h (getrandom): Override if REPLACE_GETRANDOM is 1. * lib/getrandom.c (getrandom): When the system has getrandom, just invoke it. * m4/getrandom.m4 (gl_FUNC_GETRANDOM): Set REPLACE_GETRANDOM if the system's getrandom function's prototype is not the expected one. * m4/sys_random_h.m4 (gl_SYS_RANDOM_H_DEFAULTS): Initialize REPLACE_GETRANDOM. * modules/sys_random (Makefile.am): Substitute REPLACE_GETRANDOM. * modules/getrandom (modules/getrandom): Consider REPLACE_GETRANDOM. * tests/test-getrandom.c (main): Allow error EINVAL as an alternative to EAGAIN. * doc/glibc-functions/getrandom.texi: Mention the new module and the Solaris problem. diff --git a/doc/glibc-functions/getrandom.texi b/doc/glibc-functions/getrandom.texi index 2f4debc..2d93556 100644 --- a/doc/glibc-functions/getrandom.texi +++ b/doc/glibc-functions/getrandom.texi @@ -15,7 +15,7 @@ Documentation: @uref{https://www.kernel.org/doc/man-pages/online/pages/man2/getrandom.2.html,,man getrandom}. @end itemize -Gnulib module: --- +Gnulib module: getrandom Portability problems fixed by Gnulib: @itemize @@ -23,6 +23,9 @@ Portability problems fixed by Gnulib: This function is missing on some platforms: glibc 2.24, Mac OS X 10.5, FreeBSD 11.0, NetBSD 5.0, OpenBSD 3.8, Solaris 11.0, Android 9.0. +@item +This function has a different return type on some platforms: +Solaris 11.4. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/getrandom.c b/lib/getrandom.c index 9b6ecb4..f20ffe0 100644 --- a/lib/getrandom.c +++ b/lib/getrandom.c @@ -21,16 +21,21 @@ #include <sys/random.h> -#include "minmax.h" #include <fcntl.h> #include <stdbool.h> #include <unistd.h> +#include "minmax.h" + /* Set BUFFER (of size LENGTH) to random bytes under the control of FLAGS. Return the number of bytes written, or -1 on error. */ ssize_t getrandom (void *buffer, size_t length, unsigned int flags) +#undef getrandom { +#if HAVE_GETRANDOM + return getrandom (buffer, length, flags); +#else static int randfd[2] = { -1, -1 }; bool devrandom = (flags & GRND_RANDOM) != 0; int fd = randfd[devrandom]; @@ -49,4 +54,5 @@ getrandom (void *buffer, size_t length, unsigned int flags) } return read (fd, buffer, length); +#endif } diff --git a/lib/sys_random.in.h b/lib/sys_random.in.h index 3997cf4..4d12db9 100644 --- a/lib/sys_random.in.h +++ b/lib/sys_random.in.h @@ -51,13 +51,25 @@ #if @GNULIB_GETRANDOM@ /* Fill a buffer with random bytes. */ -# if !@HAVE_GETRANDOM@ +# if @REPLACE_GETRANDOM@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef getrandom +# define getrandom rpl_getrandom +# endif +_GL_FUNCDECL_RPL (getrandom, ssize_t, + (void *buffer, size_t length, unsigned int flags) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (getrandom, ssize_t, + (void *buffer, size_t length, unsigned int flags)); +# else +# if !@HAVE_GETRANDOM@ _GL_FUNCDECL_SYS (getrandom, ssize_t, (void *buffer, size_t length, unsigned int flags) _GL_ARG_NONNULL ((1))); -# endif +# endif _GL_CXXALIAS_SYS (getrandom, ssize_t, (void *buffer, size_t length, unsigned int flags)); +# endif _GL_CXXALIASWARN (getrandom); #elif defined GNULIB_POSIXCHECK # undef getrandom diff --git a/m4/getrandom.m4 b/m4/getrandom.m4 index 79e5520..9fee059 100644 --- a/m4/getrandom.m4 +++ b/m4/getrandom.m4 @@ -1,4 +1,4 @@ -# getrandom.m4 serial 2 +# getrandom.m4 serial 3 dnl Copyright 2020 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -12,5 +12,23 @@ AC_DEFUN([gl_FUNC_GETRANDOM], AC_CHECK_FUNCS_ONCE([getrandom]) if test "$ac_cv_func_getrandom" != yes; then HAVE_GETRANDOM=0 + else + dnl On Solaris 11.4 the return type is 'int', not 'ssize_t'. + AC_CACHE_CHECK([whether getrandom is compatible with its GNU+BSD signature], + [gl_cv_func_getrandom_ok], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <sys/random.h> + #include <sys/types.h> + ssize_t getrandom (void *, size_t, unsigned int); + ]], + [[]]) + ], + [gl_cv_func_getrandom_ok=yes], + [gl_cv_func_getrandom_ok=no]) + ]) + if test $gl_cv_func_getrandom_ok = no; then + REPLACE_GETRANDOM=1 + fi fi ]) diff --git a/m4/sys_random_h.m4 b/m4/sys_random_h.m4 index d78307f..2ab96ef 100644 --- a/m4/sys_random_h.m4 +++ b/m4/sys_random_h.m4 @@ -1,4 +1,4 @@ -# sys_random_h.m4 serial 1 +# sys_random_h.m4 serial 2 dnl Copyright (C) 2020 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,4 +40,5 @@ AC_DEFUN([gl_SYS_RANDOM_H_DEFAULTS], GNULIB_GETRANDOM=0; AC_SUBST([GNULIB_GETRANDOM]) dnl Assume proper GNU behavior unless another module says otherwise. HAVE_GETRANDOM=1; AC_SUBST([HAVE_GETRANDOM]) + REPLACE_GETRANDOM=1; AC_SUBST([REPLACE_GETRANDOM]) ]) diff --git a/modules/getrandom b/modules/getrandom index f7b3ff9..e94686d 100644 --- a/modules/getrandom +++ b/modules/getrandom @@ -8,13 +8,13 @@ m4/getrandom.m4 Depends-on: sys_random crypto/gc-random [test $HAVE_GETRANDOM = 0] -fcntl-h [test $HAVE_GETRANDOM = 0] -minmax [test $HAVE_GETRANDOM = 0] -open [test $HAVE_GETRANDOM = 0] +fcntl-h [test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1] +minmax [test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1] +open [test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1] configure.ac: gl_FUNC_GETRANDOM -if test $HAVE_GETRANDOM = 0; then +if test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1; then AC_LIBOBJ([getrandom]) fi gl_SYS_RANDOM_MODULE_INDICATOR([getrandom]) diff --git a/modules/sys_random b/modules/sys_random index 1d0eb7c..b88507b 100644 --- a/modules/sys_random +++ b/modules/sys_random @@ -32,6 +32,7 @@ sys/random.h: sys_random.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_N -e 's|@''HAVE_SYS_RANDOM_H''@|$(HAVE_SYS_RANDOM_H)|g' \ -e 's/@''GNULIB_GETRANDOM''@/$(GNULIB_GETRANDOM)/g' \ -e 's/@''HAVE_GETRANDOM''@/$(HAVE_GETRANDOM)/g' \ + -e 's/@''REPLACE_GETRANDOM''@/$(REPLACE_GETRANDOM)/g' \ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ diff --git a/tests/test-getrandom.c b/tests/test-getrandom.c index 3c84f87..8b25958 100644 --- a/tests/test-getrandom.c +++ b/tests/test-getrandom.c @@ -75,7 +75,8 @@ main (void) ret = getrandom (large_buf, sizeof (large_buf), GRND_RANDOM | GRND_NONBLOCK); /* It is very unlikely that so many truly random bytes were ready. */ if (ret < 0) - ASSERT (errno == ENOSYS || errno == EAGAIN); + ASSERT (errno == ENOSYS || errno == EAGAIN + || errno == EINVAL /* Solaris */); else ASSERT (ret > 0 && ret < sizeof (large_buf));