Extend tst-{atexit,at_quick_exit,cxa_atexit,onexit} to verify inheritance across fork

Message ID CALoOobNv3GUJEatKp-36VuepLbbpjqgmfKngkwY2hD_nPfhJ8w@mail.gmail.com
State Committed
Commit 8325b477b14353aa62192d0fdc7e883e5ced75d1
Headers

Commit Message

Paul Pluzhnikov Aug. 28, 2017, 5:16 p.m. UTC
  Greetings,

Attached patch implements one of the TODOs in stdlib/tst-atexit-common.c


2017-08-28  Paul Pluzhnikov  <ppluzhnikov@google.com>

        * stdlib/tst-atexit-common.c (do_test): Test handler inheritance
        by child.
  

Comments

Carlos O'Donell Aug. 28, 2017, 7:47 p.m. UTC | #1
On 08/28/2017 01:16 PM, Paul Pluzhnikov wrote:
> Greetings,
> 
> Attached patch implements one of the TODOs in stdlib/tst-atexit-common.c
> 
> 
> 2017-08-28  Paul Pluzhnikov  <ppluzhnikov@google.com>
> 
>         * stdlib/tst-atexit-common.c (do_test): Test handler inheritance
>         by child.
> 

This looks good to me.

Thanks for adding the child inheritance test.

Checking for ATEXIT_MAX shouldn't be too much harder... ;-)

Cheers,
Carlos.
  
Florian Weimer Aug. 28, 2017, 8:01 p.m. UTC | #2
On 08/28/2017 09:47 PM, Carlos O'Donell wrote:

> Checking for ATEXIT_MAX shouldn't be too much harder... ;-)

POSIX does not allow us to define _SC_ATEXIT_MAX because there is no
actual limit (beyond available memory).  The INT_MAX return value is a bug.

I filed a bug: https://sourceware.org/bugzilla/show_bug.cgi?id=22020

Thanks,
Florian
  
Carlos O'Donell Aug. 28, 2017, 8:38 p.m. UTC | #3
On 08/28/2017 04:01 PM, Florian Weimer wrote:
> On 08/28/2017 09:47 PM, Carlos O'Donell wrote:
> 
>> Checking for ATEXIT_MAX shouldn't be too much harder... ;-)
> 
> POSIX does not allow us to define _SC_ATEXIT_MAX because there is no
> actual limit (beyond available memory).  The INT_MAX return value is a bug.

My apologies, I should have been clearer.

The test case *must* test that you can at least register 32 handlers without
error since POSIX Issue 7 mandates this is the minimum number that must be
supported. This way the test case checks for the minimum.

We don't need to check the maximum. Checking for the maximum is more expensive
than just making sure you can register and call 32 handlers.

> I filed a bug: https://sourceware.org/bugzilla/show_bug.cgi?id=22020

Now you've added the need for another test case which should verify that
_SC_ATEXIT_MAX returns -1?

Cheers,
Carlos.
  

Patch

diff --git a/stdlib/tst-atexit-common.c b/stdlib/tst-atexit-common.c
index 262235a478..99b00bf3aa 100644
--- a/stdlib/tst-atexit-common.c
+++ b/stdlib/tst-atexit-common.c
@@ -21,11 +21,20 @@ 
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/wait.h>
 
 #define MAX_ATEXIT 20  /* Large enough for current set of invocations.  */
 static char crumbs[MAX_ATEXIT];
 static int next_slot = 0;
 
+/* Helper: flush stdout and _exit.  */
+static void
+_exit_with_flush (int code)
+{
+  fflush (stdout);
+  _exit (code);
+}
+
 static void
 fn0 (void)
 {
@@ -60,11 +69,11 @@  fn_final (void)
   const char expected[] = "3021121130211";
 
   if (strcmp (crumbs, expected) == 0)
-    _exit (0);
+    _exit_with_flush (0);
 
   printf ("crumbs:   %s\n", crumbs);
   printf ("expected: %s\n", expected);
-  _exit (1);
+  _exit_with_flush (1);
 }
 
 /* This is currently just a basic test to verify that exit handlers execute
@@ -72,8 +81,7 @@  fn_final (void)
 
    TODO: Additional tests that we should do:
    1. POSIX says we need to support at least ATEXIT_MAX
-   2. Verify that fork'd child inherit the registrations of the parent.
-   3. ...  */
+   2. ...  */
 
 static int
 do_test (void)
@@ -88,6 +96,40 @@  do_test (void)
   ATEXIT (fn1);
   ATEXIT (fn3);
 
+  /* Verify that handlers registered above are inherited across fork.  */
+  const pid_t child = fork ();
+  switch (child)
+    {
+    case -1:
+      printf ("fork: %m\n");
+      _exit_with_flush (3);
+    case 0:  /* Child.  */
+      break;
+    default:
+      {
+	int status;
+	const pid_t exited = waitpid (child, &status, 0);
+	if (child != exited)
+	  {
+	    printf ("unexpected child: %d, expected %d\n", exited, child);
+	    _exit_with_flush (4);
+	  }
+	if (status != 0)
+	  {
+	    if (WIFEXITED (status))
+	      printf ("unexpected exit status %d from child %d\n",
+		      WEXITSTATUS (status), child);
+	    else if (WIFSIGNALED (status))
+	      printf ("unexpected signal %d from child %d\n",
+		      WTERMSIG (status), child);
+	    else
+	      printf ("unexpected status %d from child %d\n", status, child);
+	    _exit_with_flush (5);
+	  }
+      }
+      break;
+    }
+
   EXIT (2);  /* If we see this exit code, fn_final must have not worked.  */
 }