1 /* Test that subprocesses generate distinct streams of randomness.
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
19 /* Collect random data from subprocesses and check that all the
20 results are unique. */
22 #include <array_length.h>
26 #include <support/check.h>
27 #include <support/support.h>
28 #include <support/xthread.h>
29 #include <support/xunistd.h>
32 /* Perform multiple runs. The subsequent runs start with an
33 already-initialized random number generator. (The number 1500 was
34 seen to reproduce failures reliable in case of a race condition in
35 the fork detection code.) */
38 /* One hundred processes in total. This should be high enough to
39 expose any issues, but low enough not to tax the overall system too
41 enum { subprocesses
= 49 };
43 /* The total number of processes. */
44 enum { processes
= subprocesses
+ 1 };
46 /* Number of bytes of randomness to generate per process. Large
47 enough to make false positive duplicates extremely unlikely. */
48 enum { random_size
= 16 };
50 /* Generated bytes of randomness. */
53 unsigned char bytes
[random_size
];
56 /* Shared across all processes. */
57 static struct shared_data
59 pthread_barrier_t barrier
;
60 struct result results
[runs
][processes
];
64 generate_arc4random (unsigned char *bytes
)
66 for (int i
= 0; i
< random_size
/ sizeof (uint32_t); i
++)
68 uint32_t x
= arc4random ();
69 memcpy (&bytes
[4 * i
], &x
, sizeof x
);
74 generate_arc4random_buf (unsigned char *bytes
)
76 arc4random_buf (bytes
, random_size
);
80 generate_arc4random_uniform (unsigned char *bytes
)
82 for (int i
= 0; i
< random_size
; i
++)
83 bytes
[i
] = arc4random_uniform (256);
86 /* Invoked to collect data from a subprocess. */
88 subprocess (int run
, int process_index
, void (*func
)(unsigned char *))
90 xpthread_barrier_wait (&shared_data
->barrier
);
91 func (shared_data
->results
[run
][process_index
].bytes
);
94 /* Used to sort the results. */
101 /* Used to sort an array of struct index values. */
103 index_compare (const void *left1
, const void *right1
)
105 const struct index
*left
= left1
;
106 const struct index
*right
= right1
;
108 return memcmp (shared_data
->results
[left
->run
][left
->process_index
].bytes
,
109 shared_data
->results
[right
->run
][right
->process_index
].bytes
,
114 do_test_func (void (*func
)(unsigned char *bytes
))
116 /* Collect random data. */
117 for (int run
= 0; run
< runs
; ++run
)
119 pid_t pids
[subprocesses
];
120 for (int process_index
= 0; process_index
< subprocesses
;
123 pids
[process_index
] = xfork ();
124 if (pids
[process_index
] == 0)
126 subprocess (run
, process_index
, func
);
131 /* Trigger all subprocesses. Also add data from the parent
133 subprocess (run
, subprocesses
, func
);
135 for (int process_index
= 0; process_index
< subprocesses
;
139 xwaitpid (pids
[process_index
], &status
, 0);
141 FAIL_EXIT1 ("subprocess index %d (PID %d) exit status %d\n",
142 process_index
, (int) pids
[process_index
], status
);
146 /* Check for duplicates. */
147 struct index indexes
[runs
* processes
];
148 for (int run
= 0; run
< runs
; ++run
)
149 for (int process_index
= 0; process_index
< processes
; ++process_index
)
150 indexes
[run
* processes
+ process_index
]
151 = (struct index
) { .run
= run
, .process_index
= process_index
};
152 qsort (indexes
, array_length (indexes
), sizeof (indexes
[0]), index_compare
);
153 for (size_t i
= 1; i
< array_length (indexes
); ++i
)
155 if (index_compare (indexes
+ i
- 1, indexes
+ i
) == 0)
157 support_record_failure ();
159 = shared_data
->results
[indexes
[i
].run
]
160 [indexes
[i
].process_index
].bytes
;
161 char *quoted
= support_quote_blob (bytes
, random_size
);
162 printf ("error: duplicate randomness data: \"%s\"\n"
163 " run %d, subprocess %d\n"
164 " run %d, subprocess %d\n",
165 quoted
, indexes
[i
- 1].run
, indexes
[i
- 1].process_index
,
166 indexes
[i
].run
, indexes
[i
].process_index
);
177 shared_data
= support_shared_allocate (sizeof (*shared_data
));
179 pthread_barrierattr_t attr
;
180 xpthread_barrierattr_init (&attr
);
181 xpthread_barrierattr_setpshared (&attr
, PTHREAD_PROCESS_SHARED
);
182 xpthread_barrier_init (&shared_data
->barrier
, &attr
, processes
);
183 xpthread_barrierattr_destroy (&attr
);
186 do_test_func (generate_arc4random
);
187 do_test_func (generate_arc4random_buf
);
188 do_test_func (generate_arc4random_uniform
);
190 xpthread_barrier_destroy (&shared_data
->barrier
);
191 support_shared_free (shared_data
);
198 #include <support/test-driver.c>