tst-mallocfork2.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* Test case for async-signal-safe fork (with respect to malloc).
  2. Copyright (C) 2016-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; see the file COPYING.LIB. If
  14. not, see <http://www.gnu.org/licenses/>. */
  15. /* This test will fail if the process is multi-threaded because we
  16. only have an async-signal-safe fork in the single-threaded case
  17. (where we skip acquiring the malloc heap locks).
  18. This test only checks async-signal-safety with regards to malloc;
  19. other, more rarely-used glibc subsystems could have locks which
  20. still make fork unsafe, even in single-threaded processes. */
  21. #include <errno.h>
  22. #include <sched.h>
  23. #include <signal.h>
  24. #include <stdbool.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/wait.h>
  29. #include <time.h>
  30. #include <unistd.h>
  31. /* How many malloc objects to keep arond. */
  32. enum { malloc_objects = 1009 };
  33. /* The maximum size of an object. */
  34. enum { malloc_maximum_size = 70000 };
  35. /* How many signals need to be delivered before the test exits. */
  36. enum { signal_count = 1000 };
  37. static int do_test (void);
  38. #define TIMEOUT 100
  39. #define TEST_FUNCTION do_test ()
  40. #include "../test-skeleton.c"
  41. /* Process ID of the subprocess which sends SIGUSR1 signals. */
  42. static pid_t sigusr1_sender_pid;
  43. /* Set to 1 if SIGUSR1 is received. Used to detect a signal during
  44. malloc/free. */
  45. static volatile sig_atomic_t sigusr1_received;
  46. /* Periodically set to 1, to indicate that the process is making
  47. progress. Checked by liveness_signal_handler. */
  48. static volatile sig_atomic_t progress_indicator = 1;
  49. static void
  50. sigusr1_handler (int signo)
  51. {
  52. /* Let the main program make progress, by temporarily suspending
  53. signals from the subprocess. */
  54. if (sigusr1_received)
  55. return;
  56. /* sigusr1_sender_pid might not be initialized in the parent when
  57. the first SIGUSR1 signal arrives. */
  58. if (sigusr1_sender_pid > 0 && kill (sigusr1_sender_pid, SIGSTOP) != 0)
  59. {
  60. write_message ("error: kill (SIGSTOP)\n");
  61. abort ();
  62. }
  63. sigusr1_received = 1;
  64. /* Perform a fork with a trivial subprocess. */
  65. pid_t pid = fork ();
  66. if (pid == -1)
  67. {
  68. write_message ("error: fork\n");
  69. abort ();
  70. }
  71. if (pid == 0)
  72. _exit (0);
  73. int status;
  74. int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
  75. if (ret < 0)
  76. {
  77. write_message ("error: waitpid\n");
  78. abort ();
  79. }
  80. if (status != 0)
  81. {
  82. write_message ("error: unexpected exit status from subprocess\n");
  83. abort ();
  84. }
  85. }
  86. static void
  87. liveness_signal_handler (int signo)
  88. {
  89. if (progress_indicator)
  90. progress_indicator = 0;
  91. else
  92. write_message ("warning: process seems to be stuck\n");
  93. }
  94. static void
  95. __attribute__ ((noreturn))
  96. signal_sender (int signo, bool sleep)
  97. {
  98. pid_t target = getppid ();
  99. while (true)
  100. {
  101. if (kill (target, signo) != 0)
  102. {
  103. dprintf (STDOUT_FILENO, "error: kill: %m\n");
  104. abort ();
  105. }
  106. if (sleep)
  107. usleep (1 * 1000 * 1000);
  108. else
  109. /* Reduce the rate at which we send signals. */
  110. sched_yield ();
  111. }
  112. }
  113. static int
  114. do_test (void)
  115. {
  116. struct sigaction action =
  117. {
  118. .sa_handler = sigusr1_handler,
  119. };
  120. sigemptyset (&action.sa_mask);
  121. if (sigaction (SIGUSR1, &action, NULL) != 0)
  122. {
  123. printf ("error: sigaction: %m");
  124. return 1;
  125. }
  126. action.sa_handler = liveness_signal_handler;
  127. if (sigaction (SIGUSR2, &action, NULL) != 0)
  128. {
  129. printf ("error: sigaction: %m");
  130. return 1;
  131. }
  132. pid_t sigusr2_sender_pid = fork ();
  133. if (sigusr2_sender_pid == 0)
  134. signal_sender (SIGUSR2, true);
  135. sigusr1_sender_pid = fork ();
  136. if (sigusr1_sender_pid == 0)
  137. signal_sender (SIGUSR1, false);
  138. void *objects[malloc_objects] = {};
  139. unsigned signals = 0;
  140. unsigned seed = 1;
  141. time_t last_report = 0;
  142. while (signals < signal_count)
  143. {
  144. progress_indicator = 1;
  145. int slot = rand_r (&seed) % malloc_objects;
  146. size_t size = rand_r (&seed) % malloc_maximum_size;
  147. if (kill (sigusr1_sender_pid, SIGCONT) != 0)
  148. {
  149. printf ("error: kill (SIGCONT): %m\n");
  150. signal (SIGUSR1, SIG_IGN);
  151. kill (sigusr1_sender_pid, SIGKILL);
  152. kill (sigusr2_sender_pid, SIGKILL);
  153. return 1;
  154. }
  155. sigusr1_received = false;
  156. free (objects[slot]);
  157. objects[slot] = malloc (size);
  158. if (sigusr1_received)
  159. {
  160. ++signals;
  161. time_t current = time (0);
  162. if (current != last_report)
  163. {
  164. printf ("info: SIGUSR1 signal count: %u\n", signals);
  165. last_report = current;
  166. }
  167. }
  168. if (objects[slot] == NULL)
  169. {
  170. printf ("error: malloc: %m\n");
  171. signal (SIGUSR1, SIG_IGN);
  172. kill (sigusr1_sender_pid, SIGKILL);
  173. kill (sigusr2_sender_pid, SIGKILL);
  174. return 1;
  175. }
  176. }
  177. /* Clean up allocations. */
  178. for (int slot = 0; slot < malloc_objects; ++slot)
  179. free (objects[slot]);
  180. /* Terminate the signal-sending subprocess. The SIGUSR1 handler
  181. should no longer run because it uses sigusr1_sender_pid. */
  182. signal (SIGUSR1, SIG_IGN);
  183. kill (sigusr1_sender_pid, SIGKILL);
  184. kill (sigusr2_sender_pid, SIGKILL);
  185. return 0;
  186. }