bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

open, openat: really support O_CLOEXEC


From: Bruno Haible
Subject: open, openat: really support O_CLOEXEC
Date: Sun, 24 May 2020 20:28:27 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-177-generic; KDE/5.18.0; x86_64; ; )

While working on support for mode 'e' in fopen(), I noticed that on macOS 10.13
open with O_CLOEXEC creates a file descriptor that does *not* have the
FD_CLOEXEC flag set.

This was meant to be implemented since 2017-08-14, but it does not work.

The problem is in this code (lib/open.c):

  fd = orig_open (filename,
                  flags & ~(have_cloexec <= 0 ? O_CLOEXEC : 0), mode);

  if (flags & O_CLOEXEC)
    {
      if (! have_cloexec)
        {
          if (0 <= fd)
            have_cloexec = 1;
          else if (errno == EINVAL)
            {
              fd = orig_open (filename, flags & ~O_CLOEXEC, mode);
              have_cloexec = -1;
            }
        }
      if (have_cloexec < 0 && 0 <= fd)
        set_cloexec_flag (fd, true);
    }

At the first invocation:
  - have_cloexec is 0,
  - thus the flags passed to orig_open() do NOT include O_CLOEXEC,
  - thus orig_open() returns an fd >= 0,
  - thus have_cloexec gets set to 1.
The detection of a platform without O_CLOEXEC support is not working.

In fact, when I extend the unit test of open(), I see it fail:

$ ./test-open
../../gltests/test-open.h:100: assertion '(flags & FD_CLOEXEC) != 0' failed
Abort trap: 6
$ ./test-openat
../../gltests/test-open.h:100: assertion '(flags & FD_CLOEXEC) != 0' failed
Abort trap: 6


This patch fixes the issue and adds the corresponding unit test.


2020-05-24  Bruno Haible  <address@hidden>

        open, openat: Really support O_CLOEXEC.
        * lib/open.c (open): When have_cloexec is still undecided, do pass a
        O_CLOEXEC flag to orig_open.
        * lib/openat.c (rpl_openat): When have_cloexec is still undecided, do
        pass a O_CLOEXEC flag to orig_openat.
        * tests/test-open.h (test_open): Verify that O_CLOEXEC is honoured.
        * modules/open-tests (Depends-on): Add fcntl.
        * modules/openat-tests (Depends-on): Likewise.
        * modules/fcntl-safer-tests (Depends-on): Likewise.

diff --git a/lib/open.c b/lib/open.c
index bb180fd..751b42d 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -124,7 +124,7 @@ open (const char *filename, int flags, ...)
 #endif
 
   fd = orig_open (filename,
-                  flags & ~(have_cloexec <= 0 ? O_CLOEXEC : 0), mode);
+                  flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
 
   if (flags & O_CLOEXEC)
     {
diff --git a/lib/openat.c b/lib/openat.c
index 974f1a8..fbe1d2e 100644
--- a/lib/openat.c
+++ b/lib/openat.c
@@ -114,7 +114,7 @@ rpl_openat (int dfd, char const *filename, int flags, ...)
 # endif
 
   fd = orig_openat (dfd, filename,
-                    flags & ~(have_cloexec <= 0 ? O_CLOEXEC : 0), mode);
+                    flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
 
   if (flags & O_CLOEXEC)
     {
diff --git a/tests/test-open.h b/tests/test-open.h
index c57054f..862c8df 100644
--- a/tests/test-open.h
+++ b/tests/test-open.h
@@ -88,6 +88,26 @@ test_open (int (*func) (char const *, int, ...), bool print)
   ASSERT (0 <= fd);
   ASSERT (close (fd) == 0);
 
+  /* O_CLOEXEC must be honoured.  */
+  if (O_CLOEXEC)
+    {
+      /* Since the O_CLOEXEC handling goes through a special code path at its
+         first invocation, test it twice.  */
+      int i;
+
+      for (i = 0; i < 2; i++)
+        {
+          int flags;
+
+          fd = func (BASE "file", O_CLOEXEC | O_RDONLY);
+          ASSERT (0 <= fd);
+          flags = fcntl (fd, F_GETFD);
+          ASSERT (flags >= 0);
+          ASSERT ((flags & FD_CLOEXEC) != 0);
+          ASSERT (close (fd) == 0);
+        }
+    }
+
   /* Symlink handling, where supported.  */
   if (symlink (BASE "file", BASE "link") != 0)
     {
diff --git a/modules/fcntl-safer-tests b/modules/fcntl-safer-tests
index cb35aed..b967c8a 100644
--- a/modules/fcntl-safer-tests
+++ b/modules/fcntl-safer-tests
@@ -5,6 +5,7 @@ tests/macros.h
 
 Depends-on:
 stdbool
+fcntl
 symlink
 
 configure.ac:
diff --git a/modules/open-tests b/modules/open-tests
index 5bc4e0f..b2b6710 100644
--- a/modules/open-tests
+++ b/modules/open-tests
@@ -6,6 +6,7 @@ tests/macros.h
 
 Depends-on:
 stdbool
+fcntl
 symlink
 
 configure.ac:
diff --git a/modules/openat-tests b/modules/openat-tests
index 0b7370d..c4a72f5 100644
--- a/modules/openat-tests
+++ b/modules/openat-tests
@@ -5,6 +5,7 @@ tests/signature.h
 tests/macros.h
 
 Depends-on:
+fcntl
 symlink
 
 configure.ac:




reply via email to

[Prev in Thread] Current Thread [Next in Thread]