futimens on musl libc (fwd)

Submitted by Rich Felker on March 24, 2019, 2:21 p.m.

Details

Message ID 20190324142118.GS23599@brightrain.aerifal.cx
State New
Series "futimens on musl libc (fwd)"
Headers show

Commit Message

Rich Felker March 24, 2019, 2:21 p.m.
I think this needs action but I'm not clear what the exact mechanism
is yet, so I'm forwarding to the list.

----- Forwarded message from Bruno Haible <bruno@clisp.org> -----

From: Bruno Haible <bruno@clisp.org>
To: bug-gnulib@gnu.org, Rich Felker <dalias@libc.org>
Subject: futimens on musl libc
Date: Sat, 23 Mar 2019 21:40:33 +0100
Message-ID: <4061903.SY8uJAIc8I@omega>

The gnulib configure test in m4/futimens.m4, when run on Alpine Linux 3.7,
determines that the errno value is not as expected for a wrong fd.

Let me document this in gnulib and update the cross-compilation guess
accordingly.

Rich, FYI: The test program is this one:

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
int main ()
{
      struct timespec ts[2];
      int fd = creat ("conftest.file", 0600);
      struct stat st;
      if (fd < 0) return 1;
      ts[0].tv_sec = 1;
      ts[0].tv_nsec = UTIME_OMIT;
      ts[1].tv_sec = 1;
      ts[1].tv_nsec = UTIME_NOW;
      errno = 0;
      if (futimens (AT_FDCWD, NULL) == 0) return 2;
      if (errno != EBADF) return 3;     /* <== It fails here */
      if (futimens (fd, ts)) return 4;
      sleep (1);
      ts[0].tv_nsec = UTIME_NOW;
      ts[1].tv_nsec = UTIME_OMIT;
      if (futimens (fd, ts)) return 5;
      if (fstat (fd, &st)) return 6;
      if (st.st_ctime < st.st_atime) return 7;
      return 0;
}


2019-03-23  Bruno Haible  <bruno@clisp.org>

	futimens: Document musl libc bug.
	* doc/posix-functions/futimens.texi: Mention the bug.
	* m4/futimens.m4 (gl_FUNC_FUTIMENS): Require AC_CANONICAL_HOST. When
	cross-compiling guess no on glibc and musl systems.


----- End forwarded message -----

Patch hide | download patch | download mbox

diff --git a/doc/posix-functions/futimens.texi b/doc/posix-functions/futimens.texi
index 19fb84e..1e1c76c 100644
--- a/doc/posix-functions/futimens.texi
+++ b/doc/posix-functions/futimens.texi
@@ -29,7 +29,7 @@  Linux kernel 2.6.32, Solaris 11.1.
 @item
 Passing @code{AT_FDCWD} as the fd argument does not properly fail with
 @code{EBADF} on some systems:
-glibc 2.11, Solaris 11.
+glibc 2.11, musl libc, Solaris 11.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/m4/futimens.m4 b/m4/futimens.m4
index 3cfa4a1..b5f4be9 100644
--- a/m4/futimens.m4
+++ b/m4/futimens.m4
@@ -1,4 +1,4 @@ 
-# serial 7
+# serial 8
 # See if we need to provide futimens replacement.
 
 dnl Copyright (C) 2009-2019 Free Software Foundation, Inc.
@@ -11,6 +11,7 @@  dnl with or without modifications, as long as this notice is preserved.
 AC_DEFUN([gl_FUNC_FUTIMENS],
 [
   AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_FUNCS_ONCE([futimens])
   if test $ac_cv_func_futimens = no; then
@@ -44,10 +45,21 @@  AC_DEFUN([gl_FUNC_FUTIMENS],
       ]])],
          [gl_cv_func_futimens_works=yes],
          [gl_cv_func_futimens_works=no],
-         [gl_cv_func_futimens_works="guessing yes"])
+         [case "$host_os" in
+                           # Guess no on glibc systems.
+            *-gnu* | gnu*) gl_cv_func_futimens_works="guessing no" ;;
+                           # Guess no on musl systems.
+            *-musl*)       gl_cv_func_futimens_works="guessing no" ;;
+                           # Guess yes otherwise.
+            *)             gl_cv_func_futimens_works="guessing yes" ;;
+          esac
+         ])
       rm -f conftest.file])
-    if test "$gl_cv_func_futimens_works" = no; then
-      REPLACE_FUTIMENS=1
-    fi
+    case "$gl_cv_func_futimens_works" in
+      *yes) ;;
+      *)
+        REPLACE_FUTIMENS=1
+        ;;
+    esac
   fi
 ])

Comments

Markus Wichmann March 24, 2019, 6:42 p.m.
On Sun, Mar 24, 2019 at 10:21:18AM -0400, Rich Felker wrote:
> I think this needs action but I'm not clear what the exact mechanism
> is yet, so I'm forwarding to the list.
>
> ----- Forwarded message from Bruno Haible <bruno@clisp.org> -----
>
> From: Bruno Haible <bruno@clisp.org>
> To: bug-gnulib@gnu.org, Rich Felker <dalias@libc.org>
> Subject: futimens on musl libc
> Date: Sat, 23 Mar 2019 21:40:33 +0100
> Message-ID: <4061903.SY8uJAIc8I@omega>
>
> The gnulib configure test in m4/futimens.m4, when run on Alpine Linux 3.7,
> determines that the errno value is not as expected for a wrong fd.
>
> Let me document this in gnulib and update the cross-compilation guess
> accordingly.
>
> Rich, FYI: The test program is this one:
>
> #include <fcntl.h>
> #include <sys/stat.h>
> #include <unistd.h>
> #include <time.h>
> #include <errno.h>
> int main ()
> {
>       struct timespec ts[2];
>       int fd = creat ("conftest.file", 0600);
>       struct stat st;
>       if (fd < 0) return 1;
>       ts[0].tv_sec = 1;
>       ts[0].tv_nsec = UTIME_OMIT;
>       ts[1].tv_sec = 1;
>       ts[1].tv_nsec = UTIME_NOW;
>       errno = 0;
>       if (futimens (AT_FDCWD, NULL) == 0) return 2;
>       if (errno != EBADF) return 3;     /* <== It fails here */

Ah! There are multiple errors present in the call, but gnulib expects a
certain one of these to be returned.

futimens() should return EBADF for invalid FD, and EFAULT for invalid
buffer address (second argument, according to manpage). However, musl
implements futimens in terms of utimensat(), which just wraps a syscall
of the same name on recent kernels (i.e. there's an optional fallback
there that won't be used if the error from the first try isn't ENOSYS).

According to the manpage, utimensat() returns EFAULT for invalid buffer
address, and if the fd happens to be AT_FDCWD, but the path name is NULL
(which it is when the call comes in from futimens()).

POSIX is also rather clear on the matter:
|The futimens() function shall fail if:
|
|[EBADF]
|    The fd argument is not a valid file descriptor.

If the test program were patched to provide a propper buffer to
futimens(), musl's implementation would still return EFAULT instead of
the required EBADF. We might have to test for AT_FDCWD in futimens(),
before passing it on to utimensat(). Are there other special FDs we have
to consider?

Ciao,
Markus