1 /* Test concurrent fork, getline, and fflush (NULL).
2    Copyright (C) 2016-2022 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 License as
7    published by the Free Software Foundation; either version 2.1 of the
8    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; see the file COPYING.LIB.  If
17    not, see <https://www.gnu.org/licenses/>.  */
18 
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <pthread.h>
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include <malloc.h>
27 #include <time.h>
28 #include <string.h>
29 #include <signal.h>
30 
31 #include <support/xthread.h>
32 #include <support/temp_file.h>
33 #include <support/test-driver.h>
34 
35 enum {
36   /* Number of threads which call fork.  */
37   fork_thread_count = 4,
38   /* Number of threads which call getline (and, indirectly,
39      malloc).  */
40   read_thread_count = 8,
41 };
42 
43 static bool termination_requested;
44 
45 static void *
fork_thread_function(void * closure)46 fork_thread_function (void *closure)
47 {
48   while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
49     {
50       pid_t pid = fork ();
51       if (pid < 0)
52         {
53           printf ("error: fork: %m\n");
54           abort ();
55         }
56       else if (pid == 0)
57         _exit (17);
58 
59       int status;
60       if (waitpid (pid, &status, 0) < 0)
61         {
62           printf ("error: waitpid: %m\n");
63           abort ();
64         }
65       if (!WIFEXITED (status) || WEXITSTATUS (status) != 17)
66         {
67           printf ("error: waitpid returned invalid status: %d\n", status);
68           abort ();
69         }
70     }
71   return NULL;
72 }
73 
74 static char *file_to_read;
75 
76 static void *
read_thread_function(void * closure)77 read_thread_function (void *closure)
78 {
79   FILE *f = fopen (file_to_read, "r");
80   if (f == NULL)
81     {
82       printf ("error: fopen (%s): %m\n", file_to_read);
83       abort ();
84     }
85 
86   while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
87     {
88       rewind (f);
89       char *line = NULL;
90       size_t line_allocated = 0;
91       ssize_t ret = getline (&line, &line_allocated, f);
92       if (ret < 0)
93         {
94           printf ("error: getline: %m\n");
95           abort ();
96         }
97       free (line);
98     }
99   fclose (f);
100 
101   return NULL;
102 }
103 
104 static void *
flushall_thread_function(void * closure)105 flushall_thread_function (void *closure)
106 {
107   while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
108     if (fflush (NULL) != 0)
109       {
110         printf ("error: fflush (NULL): %m\n");
111         abort ();
112       }
113   return NULL;
114 }
115 
116 static void
create_threads(pthread_t * threads,size_t count,void * (* func)(void *))117 create_threads (pthread_t *threads, size_t count, void *(*func) (void *))
118 {
119   for (size_t i = 0; i < count; ++i)
120     threads[i] = xpthread_create (NULL, func, NULL);
121 }
122 
123 static void
join_threads(pthread_t * threads,size_t count)124 join_threads (pthread_t *threads, size_t count)
125 {
126   for (size_t i = 0; i < count; ++i)
127     xpthread_join (threads[i]);
128 }
129 
130 /* Create a file which consists of a single long line, and assigns
131    file_to_read.  The hope is that this triggers an allocation in
132    getline which needs a lock.  */
133 static void
create_file_with_large_line(void)134 create_file_with_large_line (void)
135 {
136   int fd = create_temp_file ("bug19431-large-line", &file_to_read);
137   if (fd < 0)
138     {
139       printf ("error: create_temp_file: %m\n");
140       abort ();
141     }
142   FILE *f = fdopen (fd, "w+");
143   if (f == NULL)
144     {
145       printf ("error: fdopen: %m\n");
146       abort ();
147     }
148   for (int i = 0; i < 50000; ++i)
149     fputc ('x', f);
150   fputc ('\n', f);
151   if (ferror (f))
152     {
153       printf ("error: fputc: %m\n");
154       abort ();
155     }
156   if (fclose (f) != 0)
157     {
158       printf ("error: fclose: %m\n");
159       abort ();
160     }
161 }
162 
163 static int
do_test(void)164 do_test (void)
165 {
166   /* Make sure that we do not exceed the arena limit with the number
167      of threads we configured.  */
168   if (mallopt (M_ARENA_MAX, 400) == 0)
169     {
170       printf ("error: mallopt (M_ARENA_MAX) failed\n");
171       return 1;
172     }
173 
174   /* Leave some room for shutting down all threads gracefully.  */
175   int timeout = 3;
176   if (timeout > DEFAULT_TIMEOUT)
177     timeout = DEFAULT_TIMEOUT - 1;
178 
179   create_file_with_large_line ();
180 
181   pthread_t fork_threads[fork_thread_count];
182   create_threads (fork_threads, fork_thread_count, fork_thread_function);
183   pthread_t read_threads[read_thread_count];
184   create_threads (read_threads, read_thread_count, read_thread_function);
185   pthread_t flushall_threads[1];
186   create_threads (flushall_threads, 1, flushall_thread_function);
187 
188   struct timespec ts = {timeout, 0};
189   if (nanosleep (&ts, NULL))
190     {
191       printf ("error: error: nanosleep: %m\n");
192       abort ();
193     }
194 
195   __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
196 
197   join_threads (flushall_threads, 1);
198   join_threads (read_threads, read_thread_count);
199   join_threads (fork_threads, fork_thread_count);
200 
201   free (file_to_read);
202 
203   return 0;
204 }
205 
206 #include <support/test-driver.c>
207