1 /* Test that subprocesses generate distinct streams of randomness.
2 Copyright (C) 2022-2024 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. */
36 /* Total number of spawned processes on each run. */
37 enum { subprocesses
= 49 };
39 /* The total number of processes. */
40 enum { processes
= subprocesses
+ 1 };
42 /* Number of bytes of randomness to generate per process. Large
43 enough to make false positive duplicates extremely unlikely. */
44 enum { random_size
= 16 };
46 /* Generated bytes of randomness. */
49 unsigned char bytes
[random_size
];
52 /* Shared across all processes. */
53 static struct shared_data
55 pthread_barrier_t barrier
;
56 struct result results
[runs
][processes
];
60 generate_arc4random (unsigned char *bytes
)
62 for (int i
= 0; i
< random_size
/ sizeof (uint32_t); i
++)
64 uint32_t x
= arc4random ();
65 memcpy (&bytes
[4 * i
], &x
, sizeof x
);
70 generate_arc4random_buf (unsigned char *bytes
)
72 arc4random_buf (bytes
, random_size
);
76 generate_arc4random_uniform (unsigned char *bytes
)
78 for (int i
= 0; i
< random_size
; i
++)
79 bytes
[i
] = arc4random_uniform (256);
82 /* Invoked to collect data from a subprocess. */
84 subprocess (int run
, int process_index
, void (*func
)(unsigned char *))
86 xpthread_barrier_wait (&shared_data
->barrier
);
87 func (shared_data
->results
[run
][process_index
].bytes
);
90 /* Used to sort the results. */
97 /* Used to sort an array of struct index values. */
99 index_compare (const void *left1
, const void *right1
)
101 const struct index
*left
= left1
;
102 const struct index
*right
= right1
;
104 return memcmp (shared_data
->results
[left
->run
][left
->process_index
].bytes
,
105 shared_data
->results
[right
->run
][right
->process_index
].bytes
,
110 do_test_func (void (*func
)(unsigned char *bytes
))
112 /* Collect random data. */
113 for (int run
= 0; run
< runs
; ++run
)
115 pid_t pids
[subprocesses
];
116 for (int process_index
= 0; process_index
< subprocesses
;
119 pids
[process_index
] = xfork ();
120 if (pids
[process_index
] == 0)
122 subprocess (run
, process_index
, func
);
127 /* Trigger all subprocesses. Also add data from the parent
129 subprocess (run
, subprocesses
, func
);
131 for (int process_index
= 0; process_index
< subprocesses
;
135 xwaitpid (pids
[process_index
], &status
, 0);
137 FAIL_EXIT1 ("subprocess index %d (PID %d) exit status %d\n",
138 process_index
, (int) pids
[process_index
], status
);
142 /* Check for duplicates. */
143 struct index indexes
[runs
* processes
];
144 for (int run
= 0; run
< runs
; ++run
)
145 for (int process_index
= 0; process_index
< processes
; ++process_index
)
146 indexes
[run
* processes
+ process_index
]
147 = (struct index
) { .run
= run
, .process_index
= process_index
};
148 qsort (indexes
, array_length (indexes
), sizeof (indexes
[0]), index_compare
);
149 for (size_t i
= 1; i
< array_length (indexes
); ++i
)
151 if (index_compare (indexes
+ i
- 1, indexes
+ i
) == 0)
153 support_record_failure ();
155 = shared_data
->results
[indexes
[i
].run
]
156 [indexes
[i
].process_index
].bytes
;
157 char *quoted
= support_quote_blob (bytes
, random_size
);
158 printf ("error: duplicate randomness data: \"%s\"\n"
159 " run %d, subprocess %d\n"
160 " run %d, subprocess %d\n",
161 quoted
, indexes
[i
- 1].run
, indexes
[i
- 1].process_index
,
162 indexes
[i
].run
, indexes
[i
].process_index
);
173 shared_data
= support_shared_allocate (sizeof (*shared_data
));
175 pthread_barrierattr_t attr
;
176 xpthread_barrierattr_init (&attr
);
177 xpthread_barrierattr_setpshared (&attr
, PTHREAD_PROCESS_SHARED
);
178 xpthread_barrier_init (&shared_data
->barrier
, &attr
, processes
);
179 xpthread_barrierattr_destroy (&attr
);
182 do_test_func (generate_arc4random
);
183 do_test_func (generate_arc4random_buf
);
184 do_test_func (generate_arc4random_uniform
);
186 xpthread_barrier_destroy (&shared_data
->barrier
);
187 support_shared_free (shared_data
);
194 #include <support/test-driver.c>