public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/azanella/atexit-order] stdlib: Testcase to show wrong atexit execution order
@ 2019-07-11 18:56 Adhemerval Zanella
  0 siblings, 0 replies; only message in thread
From: Adhemerval Zanella @ 2019-07-11 18:56 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=3cd72edf63eedb3e95ae24c974e9b500dc5c9fa0

commit 3cd72edf63eedb3e95ae24c974e9b500dc5c9fa0
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Thu Jul 11 13:45:37 2019 -0300

    stdlib: Testcase to show wrong atexit execution order
    
    This testcase is based on the one discussed on libc-help [1]
    
    [1] https://github.com/mulle-nat/ld-so-breakage
    
    The atexit calls are done by the DSO constructors and program expects
    the handlers to be executed in the reverse order the library are
    loaded.
    
    The issue is _dl_fini might re-sort the order when libraries are
    unloaded and the __cxa_finalize (called by __do_global_dtors_aux
    set in arrayfini from DSO) might in turn call its registered atexit
    in a wrong order.

Diff:
---
 stdlib/Makefile                 | 16 +++++++-
 stdlib/test-atexit-order-dabc.c | 38 +++++++++++++++++++
 stdlib/test-atexit-order-liba.c | 45 ++++++++++++++++++++++
 stdlib/test-atexit-order-libb.c | 33 +++++++++++++++++
 stdlib/test-atexit-order-libc.c | 22 +++++++++++
 stdlib/test-atexit-order-libd.c | 30 +++++++++++++++
 stdlib/test-atexit-order.c      | 82 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 265 insertions(+), 1 deletion(-)

diff --git a/stdlib/Makefile b/stdlib/Makefile
index 32f6050..fe5b39a 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -84,6 +84,7 @@ tests		:= tst-strtol tst-strtod testmb testrand testsort testdiv   \
 		   tst-cxa_atexit tst-on_exit test-atexit-race 		    \
 		   test-at_quick_exit-race test-cxa_atexit-race             \
 		   test-on_exit-race test-dlclose-exit-race 		    \
+		   test-atexit-order					    \
 		   tst-makecontext-align test-bz22786 tst-strtod-nan-sign \
 		   tst-swapcontext1 tst-setcontext4 tst-setcontext5 \
 		   tst-setcontext6 tst-setcontext7 tst-setcontext8 \
@@ -91,6 +92,7 @@ tests		:= tst-strtol tst-strtod testmb testrand testsort testdiv   \
 
 tests-internal	:= tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
 		   tst-tls-atexit tst-tls-atexit-nodelete
+others		:= test-atexit-order-dabc
 tests-static	:= tst-secure-getenv
 
 ifeq ($(build-hardcoded-path-in-tests),yes)
@@ -116,7 +118,11 @@ else
 tests-unsupported += tst-quick_exit tst-thread-quick_exit
 endif
 
-modules-names	= tst-tls-atexit-lib test-dlclose-exit-race-helper
+modules-names	= tst-tls-atexit-lib test-dlclose-exit-race-helper \
+		  test-atexit-order-liba \
+		  test-atexit-order-libb \
+		  test-atexit-order-libc \
+		  test-atexit-order-libd
 extra-test-objs += $(addsuffix .os, $(modules-names))
 
 ifeq ($(build-shared),yes)
@@ -235,6 +241,14 @@ $(objpfx)tst-tls-atexit.out: $(objpfx)tst-tls-atexit-lib.so
 $(objpfx)tst-tls-atexit-nodelete: $(shared-thread-library) $(libdl)
 $(objpfx)tst-tls-atexit-nodelete.out: $(objpfx)tst-tls-atexit-lib.so
 
+$(objpfx)test-atexit-order.out: $(objpfx)test-atexit-order-dabc
+test-atexit-order-ARGS = -- $(host-test-program-cmd)
+$(objpfx)test-atexit-order-dabc: $(objpfx)test-atexit-order-libd.so \
+			    	 $(objpfx)test-atexit-order-liba.so \
+			    	 $(objpfx)test-atexit-order-libb.so \
+			    	 $(objpfx)test-atexit-order-libc.so
+$(objpfx)test-atexit-order-libd.so: $(objpfx)test-atexit-order-libb.so
+
 $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
 	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
 		 '$(run-program-env)' '$(test-program-prefix-after-env)' \
diff --git a/stdlib/test-atexit-order-dabc.c b/stdlib/test-atexit-order-dabc.c
new file mode 100644
index 0000000..c4e666f
--- /dev/null
+++ b/stdlib/test-atexit-order-dabc.c
@@ -0,0 +1,38 @@
+/* Check atexit execution order regarding other exit types.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <errno.h>
+
+extern void set_a_exit_code (int);
+
+int main (int argc, char *argv[])
+{
+  if (argc < 2)
+    exit (EXIT_FAILURE);
+
+  int exit_code = strtol (argv[1], NULL, 10);
+  if (errno == ERANGE || exit_code < 0 || exit_code > 255)
+    exit (EXIT_FAILURE);
+
+  set_a_exit_code (exit_code);
+
+  exit (0);
+
+  return 0;
+}
diff --git a/stdlib/test-atexit-order-liba.c b/stdlib/test-atexit-order-liba.c
new file mode 100644
index 0000000..857787d
--- /dev/null
+++ b/stdlib/test-atexit-order-liba.c
@@ -0,0 +1,45 @@
+/* Helper module for atexit execution order test.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int exit_code;
+
+static void
+liba_atexit (void)
+{
+  printf ("%s\n", __func__);
+  fflush (stdout);
+  _exit (exit_code);
+}
+
+static void
+__attribute__((constructor))
+liba_constructor (void)
+{
+  printf ("%s\n", __func__);
+  atexit (liba_atexit);
+}
+
+void
+set_a_exit_code (int code)
+{
+  exit_code = code;
+}
diff --git a/stdlib/test-atexit-order-libb.c b/stdlib/test-atexit-order-libb.c
new file mode 100644
index 0000000..80845c5
--- /dev/null
+++ b/stdlib/test-atexit-order-libb.c
@@ -0,0 +1,33 @@
+/* Helper module for atexit execution order test.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void
+libb_atexit (void)
+{
+  printf ("%s\n", __func__);
+}
+
+void
+init_b (void)
+{
+  printf ("%s\n", __func__);
+  atexit (libb_atexit);
+}
diff --git a/stdlib/test-atexit-order-libc.c b/stdlib/test-atexit-order-libc.c
new file mode 100644
index 0000000..55b2933
--- /dev/null
+++ b/stdlib/test-atexit-order-libc.c
@@ -0,0 +1,22 @@
+/* Helper module for atexit execution order test.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+void
+foo_c (void)
+{
+}
diff --git a/stdlib/test-atexit-order-libd.c b/stdlib/test-atexit-order-libd.c
new file mode 100644
index 0000000..dc479e1
--- /dev/null
+++ b/stdlib/test-atexit-order-libd.c
@@ -0,0 +1,30 @@
+/* Helper module for atexit execution order test.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void init_b (void);
+
+static void
+__attribute__((constructor))
+libb_constructor (void)
+{
+  printf ("%s\n", __func__);
+  init_b ();
+}
diff --git a/stdlib/test-atexit-order.c b/stdlib/test-atexit-order.c
new file mode 100644
index 0000000..4ec4122
--- /dev/null
+++ b/stdlib/test-atexit-order.c
@@ -0,0 +1,82 @@
+/* Check atexit execution order regarding other exit types.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdlib.h>
+#include <libgen.h>
+
+#include <support/capture_subprocess.h>
+#include <support/support.h>
+#include <support/check.h>
+
+static int
+do_test (int argc, char *argv[])
+{
+  const int expected_exit_code = 32;
+  char *expected_exit_code_str;
+  char *test_path;
+
+  /* We must have
+     - one or four parameters left if called initially
+       + argv[1]:   path for ld.so        optional
+       + argv[2]:   "--library-path"      optional
+       + argv[3]:   the library path      optional
+       + argv[4/1]: the application name
+   */
+  char *spargv[6];
+  {
+    int i;
+    for (i = 0; i < argc - 2; i++)
+      spargv[i] = argv[i + 1];
+
+    test_path = xasprintf ("%s/%s", dirname (argv[i + 1]),
+			   "test-atexit-order-dabc");
+    spargv[i++] = test_path;
+
+    expected_exit_code_str = xasprintf ("%d", expected_exit_code);
+    spargv[i++] = expected_exit_code_str;
+
+    spargv[i] = NULL;
+  }
+
+  struct support_capture_subprocess result =
+    support_capture_subprogram (spargv[0], spargv);
+
+  const char expected[] = 
+    "liba_constructor\n"
+    "libb_constructor\n"
+    "init_b\n"
+    "libb_atexit\n"
+    "liba_atexit\n";
+
+  support_capture_subprocess_check (&result, "test-atexit-order",
+                                    32, sc_allow_stdout);
+
+  TEST_COMPARE_BLOB (result.out.buffer, result.out.length,
+		     expected, sizeof (expected) - 1);
+
+  support_capture_subprocess_free (&result);
+
+  free (expected_exit_code_str);
+  free (test_path);
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-07-11 18:56 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-11 18:56 [glibc/azanella/atexit-order] stdlib: Testcase to show wrong atexit execution order Adhemerval Zanella

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).