(root)/
glibc-2.38/
stdlib/
tst-atexit-common.c
       1  /* Helper file for tst-{atexit,at_quick_exit,cxa_atexit,on_exit}.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <string.h>
      23  #include <unistd.h>
      24  #include <sys/wait.h>
      25  
      26  /* http://pubs.opengroup.org/onlinepubs/000095399/functions/atexit.html
      27     requires that we support at least 32 atexit handlers.
      28  
      29     The number we actually support is limited by memory. Here we simply
      30     check that we support at least the minimum required.  */
      31  #define MAX_ATEXIT 32
      32  
      33  /* Arbitrary sequence matching current registrations.  */
      34  const char expected[] = "00000000000000000000000003021121130211";
      35  
      36  static char crumbs[sizeof (expected)];
      37  static int next_slot = 0;
      38  
      39  /* Helper: flush stdout and _exit.  */
      40  static void
      41  _exit_with_flush (int code)
      42  {
      43    fflush (stdout);
      44    _exit (code);
      45  }
      46  
      47  static void
      48  fn0 (void)
      49  {
      50    crumbs[next_slot++] = '0';
      51  }
      52  
      53  static void
      54  fn1 (void)
      55  {
      56    crumbs[next_slot++] = '1';
      57  }
      58  
      59  static void
      60  fn2 (void)
      61  {
      62    crumbs[next_slot++] = '2';
      63    ATEXIT (fn1);
      64  }
      65  
      66  static void
      67  fn3 (void)
      68  {
      69    crumbs[next_slot++] = '3';
      70    ATEXIT (fn2);
      71    ATEXIT (fn0);
      72  }
      73  
      74  static void
      75  fn_final (void)
      76  {
      77    if (strcmp (crumbs, expected) == 0)
      78      _exit_with_flush (0);
      79  
      80    printf ("crumbs:   %s\n", crumbs);
      81    printf ("expected: %s\n", expected);
      82    _exit_with_flush (1);
      83  }
      84  
      85  static int
      86  do_test (void)
      87  {
      88    int slots_remaining = MAX_ATEXIT;
      89  
      90    /* Register this first so it can verify expected order of the rest.  */
      91    ATEXIT (fn_final); --slots_remaining;
      92  
      93    ATEXIT (fn1); --slots_remaining;
      94    ATEXIT (fn3); --slots_remaining;
      95    ATEXIT (fn1); --slots_remaining;
      96    ATEXIT (fn2); --slots_remaining;
      97    ATEXIT (fn1); --slots_remaining;
      98    ATEXIT (fn3); --slots_remaining;
      99  
     100    /* Fill the rest of available slots with fn0.  */
     101    while (slots_remaining > 0)
     102      {
     103        ATEXIT (fn0); --slots_remaining;
     104      }
     105  
     106    /* Verify that handlers registered above are inherited across fork.  */
     107    const pid_t child = fork ();
     108    switch (child)
     109      {
     110      case -1:
     111        printf ("fork: %m\n");
     112        _exit_with_flush (3);
     113      case 0:  /* Child.  */
     114        break;
     115      default:
     116        {
     117  	int status;
     118  	const pid_t exited = waitpid (child, &status, 0);
     119  	if (child != exited)
     120  	  {
     121  	    printf ("unexpected child: %d, expected %d\n", exited, child);
     122  	    _exit_with_flush (4);
     123  	  }
     124  	if (status != 0)
     125  	  {
     126  	    if (WIFEXITED (status))
     127  	      printf ("unexpected exit status %d from child %d\n",
     128  		      WEXITSTATUS (status), child);
     129  	    else if (WIFSIGNALED (status))
     130  	      printf ("unexpected signal %d from child %d\n",
     131  		      WTERMSIG (status), child);
     132  	    else
     133  	      printf ("unexpected status %d from child %d\n", status, child);
     134  	    _exit_with_flush (5);
     135  	  }
     136        }
     137        break;
     138      }
     139  
     140    EXIT (2);  /* If we see this exit code, fn_final must have not worked.  */
     141  }
     142  
     143  #define TEST_FUNCTION do_test
     144  #include <support/test-driver.c>