1#! /bin/sh
2#
3# SPDX-License-Identifier: BSD-2-Clause
4#
5# Copyright (c) 2018-2021 Gavin D. Howard and contributors.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9#
10# * Redistributions of source code must retain the above copyright notice, this
11#   list of conditions and the following disclaimer.
12#
13# * Redistributions in binary form must reproduce the above copyright notice,
14#   this list of conditions and the following disclaimer in the documentation
15#   and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28#
29
30usage() {
31	printf 'usage: %s [run_tests] [generate_tests] [test_with_clang] [test_with_gcc] \n' "$script"
32	printf '          [run_sanitizers] [run_valgrind] [run_64_bit] [run_gen_script]\n'
33	printf '          [test_c11] [test_128_bit]\n'
34	exit 1
35}
36
37header() {
38
39	_header_msg="$1"
40	shift
41
42	printf '\n'
43	printf '*******************\n'
44	printf "$_header_msg"
45	printf '\n'
46	printf '*******************\n'
47	printf '\n'
48}
49
50do_make() {
51	make -j16 "$@"
52}
53
54configure() {
55
56	_configure_CFLAGS="$1"
57	shift
58
59	_configure_CC="$1"
60	shift
61
62	_configure_configure_flags="$1"
63	shift
64
65	_configure_GEN_HOST="$1"
66	shift
67
68	_configure_LONG_BIT="$1"
69	shift
70
71	if [ "$gen_tests" -eq 0 ]; then
72		_configure_configure_flags="-G $_configure_configure_flags"
73	fi
74
75	if [ "$_configure_CC" = "clang" ]; then
76		_configure_CFLAGS="$clang_flags $_configure_CFLAGS"
77	elif [ "$_configure_CC" = "gcc" ]; then
78		_configure_CFLAGS="$gcc_flags $_configure_CFLAGS"
79	fi
80
81	_configure_header=$(printf 'Running ./configure.sh %s ...' "$_configure_configure_flags")
82	_configure_header=$(printf "$_configure_header\n    CC=\"%s\"\n" "$_configure_CC")
83	_configure_header=$(printf "$_configure_header\n    CFLAGS=\"%s\"\n" "$_configure_CFLAGS")
84	_configure_header=$(printf "$_configure_header\n    LONG_BIT=%s" "$_configure_LONG_BIT")
85	_configure_header=$(printf "$_configure_header\n    GEN_HOST=%s" "$_configure_GEN_HOST")
86
87	header "$_configure_header"
88	CFLAGS="$_configure_CFLAGS" CC="$_configure_CC" GEN_HOST="$_configure_GEN_HOST" \
89		LONG_BIT="$_configure_LONG_BIT" ./configure.sh $_configure_configure_flags > /dev/null
90}
91
92build() {
93
94	_build_CFLAGS="$1"
95	shift
96
97	_build_CC="$1"
98	shift
99
100	_build_configure_flags="$1"
101	shift
102
103	_build_GEN_HOST="$1"
104	shift
105
106	_build_LONG_BIT="$1"
107	shift
108
109	configure "$_build_CFLAGS" "$_build_CC" "$_build_configure_flags" "$_build_GEN_HOST" "$_build_LONG_BIT"
110
111	_build_header=$(printf 'Building...\n    CC=%s' "$_build_CC")
112	_build_header=$(printf "$_build_header\n    CFLAGS=\"%s\"" "$_build_CFLAGS")
113	_build_header=$(printf "$_build_header\n    LONG_BIT=%s" "$_build_LONG_BIT")
114	_build_header=$(printf "$_build_header\n    GEN_HOST=%s" "$_build_GEN_HOST")
115
116	header "$_build_header"
117
118	do_make > /dev/null 2> "$scriptdir/.test.txt"
119
120	if [ -s "$scriptdir/.test.txt" ]; then
121		printf '%s generated warning(s):\n' "$_build_CC"
122		printf '\n'
123		cat "$scriptdir/.test.txt"
124		exit 1
125	fi
126}
127
128runtest() {
129
130	header "Running tests"
131
132	if [ "$#" -gt 0 ]; then
133		do_make "$@"
134	else
135		do_make test
136	fi
137}
138
139runconfigtests() {
140
141	_runconfigtests_CFLAGS="$1"
142	shift
143
144	_runconfigtests_CC="$1"
145	shift
146
147	_runconfigtests_configure_flags="$1"
148	shift
149
150	_runconfigtests_GEN_HOST="$1"
151	shift
152
153	_runconfigtests_LONG_BIT="$1"
154	shift
155
156	_runconfigtests_run_tests="$1"
157	shift
158
159	if [ "$_runconfigtests_run_tests" -ne 0 ]; then
160		_runconfigtests_header=$(printf 'Running tests with configure flags')
161	else
162		_runconfigtests_header=$(printf 'Building with configure flags')
163	fi
164
165	_runconfigtests_header=$(printf "$_runconfigtests_header \"%s\" ...\n" "$_runconfigtests_configure_flags")
166	_runconfigtests_header=$(printf "$_runconfigtests_header\n    CC=%s\n" "$_runconfigseries_CC")
167	_runconfigtests_header=$(printf "$_runconfigtests_header\n    CFLAGS=\"%s\"" "$_runconfigseries_CFLAGS")
168	_runconfigtests_header=$(printf "$_runconfigtests_header\n    LONG_BIT=%s" "$_runconfigtests_LONG_BIT")
169	_runconfigtests_header=$(printf "$_runconfigtests_header\n    GEN_HOST=%s" "$_runconfigtests_GEN_HOST")
170
171	header "$_runconfigtests_header"
172
173	build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \
174		"$_runconfigtests_configure_flags" "$_runconfigtests_GEN_HOST" \
175		"$_runconfigtests_LONG_BIT"
176
177	if [ "$_runconfigtests_run_tests" -ne 0 ]; then
178		runtest
179	fi
180
181	do_make clean
182
183	build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \
184		"$_runconfigtests_configure_flags -b" "$_runconfigtests_GEN_HOST" \
185		"$_runconfigtests_LONG_BIT"
186
187	if [ "$_runconfigtests_run_tests" -ne 0 ]; then
188		runtest
189	fi
190
191	do_make clean
192
193	build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \
194		"$_runconfigtests_configure_flags -d" "$_runconfigtests_GEN_HOST" \
195		"$_runconfigtests_LONG_BIT"
196
197	if [ "$_runconfigtests_run_tests" -ne 0 ]; then
198		runtest
199	fi
200
201	do_make clean
202}
203
204runconfigseries() {
205
206	_runconfigseries_CFLAGS="$1"
207	shift
208
209	_runconfigseries_CC="$1"
210	shift
211
212	_runconfigseries_configure_flags="$1"
213	shift
214
215	_runconfigseries_run_tests="$1"
216	shift
217
218	if [ "$run_64_bit" -ne 0 ]; then
219
220		if [ "$test_128_bit" -ne 0 ]; then
221			runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
222				"$_runconfigseries_configure_flags" 1 64 "$_runconfigseries_run_tests"
223		fi
224
225		if [ "$run_gen_script" -ne 0 ]; then
226			runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
227				"$_runconfigseries_configure_flags" 0 64 "$_runconfigseries_run_tests"
228		fi
229
230		runconfigtests "$_runconfigseries_CFLAGS -DBC_RAND_BUILTIN=0" "$_runconfigseries_CC" \
231			"$_runconfigseries_configure_flags" 1 64 "$_runconfigseries_run_tests"
232
233	fi
234
235	runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
236		"$_runconfigseries_configure_flags" 1 32 "$_runconfigseries_run_tests"
237
238	if [ "$run_gen_script" -ne 0 ]; then
239		runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
240			"$_runconfigseries_configure_flags" 0 32 "$_runconfigseries_run_tests"
241	fi
242}
243
244runtestseries() {
245
246	_runtestseries_CFLAGS="$1"
247	shift
248
249	_runtestseries_CC="$1"
250	shift
251
252	_runtestseries_configure_flags="$1"
253	shift
254
255	_runtestseries_run_tests="$1"
256	shift
257
258	_runtestseries_flags="E H N P EH EN EP HN HP NP EHN EHP ENP HNP EHNP"
259
260	runconfigseries "$_runtestseries_CFLAGS" "$_runtestseries_CC" \
261		"$_runtestseries_configure_flags" "$_runtestseries_run_tests"
262
263	for f in $_runtestseries_flags; do
264		runconfigseries "$_runtestseries_CFLAGS" "$_runtestseries_CC" \
265			"$_runtestseries_configure_flags -$f" "$_runtestseries_run_tests"
266	done
267}
268
269runlibtests() {
270
271	_runlibtests_CFLAGS="$1"
272	shift
273
274	_runlibtests_CC="$1"
275	shift
276
277	_runlibtests_configure_flags="$1"
278	shift
279
280	_runlibtests_run_tests="$1"
281	shift
282
283	_runlibtests_configure_flags="$_runlibtests_configure_flags -a"
284
285	build "$_runlibtests_CFLAGS" "$_runlibtests_CC" "$_runlibtests_configure_flags" 1 64
286
287	if [ "$_runlibtests_run_tests" -ne 0 ]; then
288		runtest
289	fi
290
291	build "$_runlibtests_CFLAGS" "$_runlibtests_CC" "$_runlibtests_configure_flags" 1 32
292
293	if [ "$_runlibtests_run_tests" -ne 0 ]; then
294		runtest
295	fi
296}
297
298runtests() {
299
300	_runtests_CFLAGS="$1"
301	shift
302
303	_runtests_CC="$1"
304	shift
305
306	_runtests_configure_flags="$1"
307	shift
308
309	_runtests_run_tests="$1"
310	shift
311
312	runtestseries "-std=c99 $_runtests_CFLAGS" "$_runtests_CC" "$_runtests_configure_flags" "$_runtests_run_tests"
313
314	if [ "$test_c11" -ne 0 ]; then
315		runtestseries "-std=c11 $_runtests_CFLAGS" "$_runtests_CC" "$_runtests_configure_flags" "$_runtests_run_tests"
316	fi
317}
318
319karatsuba() {
320
321	header "Running Karatsuba tests"
322	do_make karatsuba_test
323}
324
325vg() {
326
327	header "Running valgrind"
328
329	if [ "$run_64_bit" -ne 0 ]; then
330		_vg_bits=64
331	else
332		_vg_bits=32
333	fi
334
335	build "$debug" "gcc" "-O0 -gv" "1" "$_vg_bits"
336	runtest test
337
338	do_make clean_config
339
340	build "$debug" "gcc" "-O0 -gvb" "1" "$_vg_bits"
341	runtest test
342
343	do_make clean_config
344
345	build "$debug" "gcc" "-O0 -gvd" "1" "$_vg_bits"
346	runtest test
347
348	do_make clean_config
349}
350
351debug() {
352
353	_debug_CC="$1"
354	shift
355
356	_debug_run_tests="$1"
357	shift
358
359	runtests "$debug" "$_debug_CC" "-g" "$_debug_run_tests"
360
361	if [ "$_debug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
362		runtests "$debug -fsanitize=undefined" "$_debug_CC" "-g" "$_debug_run_tests"
363	fi
364
365	runlibtests "$debug" "$_debug_CC" "-g" "$_debug_run_tests"
366
367	if [ "$_debug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
368		runlibtests "$debug -fsanitize=undefined" "$_debug_CC" "-g" "$_debug_run_tests"
369	fi
370}
371
372release() {
373
374	_release_CC="$1"
375	shift
376
377	_release_run_tests="$1"
378	shift
379
380	runtests "$release" "$_release_CC" "-O3" "$_release_run_tests"
381
382	runlibtests "$release" "$_release_CC" "-O3" "$_release_run_tests"
383}
384
385reldebug() {
386
387	_reldebug_CC="$1"
388	shift
389
390	_reldebug_run_tests="$1"
391	shift
392
393	runtests "$debug" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
394
395	if [ "$_reldebug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
396		runtests "$debug -fsanitize=address" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
397		runtests "$debug -fsanitize=memory" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
398	fi
399
400	runlibtests "$debug" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
401
402	if [ "$_reldebug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
403		runlibtests "$debug -fsanitize=address" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
404		runlibtests "$debug -fsanitize=memory" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
405	fi
406}
407
408minsize() {
409
410	_minsize_CC="$1"
411	shift
412
413	_minsize_run_tests="$1"
414	shift
415
416	runtests "$release" "$_minsize_CC" "-Os" "$_minsize_run_tests"
417
418	runlibtests "$release" "$_minsize_CC" "-Os" "$_minsize_run_tests"
419}
420
421build_set() {
422
423	_build_set_CC="$1"
424	shift
425
426	_build_set_run_tests="$1"
427	shift
428
429	debug "$_build_set_CC" "$_build_set_run_tests"
430	release "$_build_set_CC" "$_build_set_run_tests"
431	reldebug "$_build_set_CC" "$_build_set_run_tests"
432	minsize "$_build_set_CC" "$_build_set_run_tests"
433}
434
435clang_flags="-Weverything -Wno-padded -Wno-switch-enum -Wno-format-nonliteral"
436clang_flags="$clang_flags -Wno-cast-align -Wno-missing-noreturn -Wno-disabled-macro-expansion"
437clang_flags="$clang_flags -Wno-unreachable-code -Wno-unreachable-code-return"
438clang_flags="$clang_flags -Wno-implicit-fallthrough"
439gcc_flags="-Wno-maybe-uninitialized -Wno-clobbered"
440
441cflags="-Wall -Wextra -Werror -pedantic -Wno-conditional-uninitialized"
442
443debug="$cflags -fno-omit-frame-pointer"
444release="$cflags -DNDEBUG"
445
446set -e
447
448script="$0"
449scriptdir=$(dirname "$script")
450
451if [ "$#" -gt 0 ]; then
452	run_tests="$1"
453	shift
454else
455	run_tests=1
456fi
457
458if [ "$#" -gt 0 ]; then
459	gen_tests="$1"
460	shift
461else
462	gen_tests=1
463fi
464
465if [ "$#" -gt 0 ]; then
466	test_with_clang="$1"
467	shift
468else
469	test_with_clang=1
470fi
471
472if [ "$#" -gt 0 ]; then
473	test_with_gcc="$1"
474	shift
475else
476	test_with_gcc=1
477fi
478
479if [ "$#" -gt 0 ]; then
480	run_sanitizers="$1"
481	shift
482else
483	run_sanitizers=1
484fi
485
486if [ "$#" -gt 0 ]; then
487	run_valgrind="$1"
488	shift
489else
490	run_valgrind=1
491fi
492
493if [ "$#" -gt 0 ]; then
494	run_64_bit="$1"
495	shift
496else
497	run_64_bit=1
498fi
499
500if [ "$#" -gt 0 ]; then
501	run_gen_script="$1"
502	shift
503else
504	run_gen_script=0
505fi
506
507if [ "$#" -gt 0 ]; then
508	test_c11="$1"
509	shift
510else
511	test_c11=0
512fi
513
514if [ "$#" -gt 0 ]; then
515	test_128_bit="$1"
516	shift
517else
518	test_128_bit=0
519fi
520
521if [ "$run_64_bit" -ne 0 ]; then
522	bits=64
523else
524	bits=32
525fi
526
527cd "$scriptdir"
528
529if [ "$test_with_clang" -ne 0 ]; then
530	defcc="clang"
531elif [ "$test_with_gcc" -ne 0 ]; then
532	defcc="gcc"
533else
534	defcc="c99"
535fi
536
537export ASAN_OPTIONS="abort_on_error=1,allocator_may_return_null=1"
538export UBSAN_OPTIONS="print_stack_trace=1,silence_unsigned_overflow=1"
539
540build "$debug" "$defcc" "-g" "1" "$bits"
541
542header "Running math library under --standard"
543
544printf 'quit\n' | bin/bc -ls
545
546do_make clean_tests
547
548if [ "$test_with_clang" -ne 0 ]; then
549	build_set "clang" "$run_tests"
550fi
551
552if [ "$test_with_gcc" -ne 0 ]; then
553	build_set "gcc" "$run_tests"
554fi
555
556if [ "$run_tests" -ne 0 ]; then
557
558	build "$release" "$defcc" "-O3" "1" "$bits"
559
560	karatsuba
561
562	if [ "$run_valgrind" -ne 0 -a "$test_with_gcc" -ne 0 ]; then
563		vg
564	fi
565
566	printf '\n'
567	printf 'Tests successful.\n'
568
569	set +e
570
571	command -v afl-gcc > /dev/null 2>&1
572	err="$?"
573
574	set -e
575
576	if [ "$err" -eq 0 ]; then
577
578		header "Configuring for afl-gcc..."
579
580		configure "$debug $gcc_flags -DBC_ENABLE_RAND=0" "afl-gcc" "-HNP -gO3" "1" "$bits"
581
582		printf '\n'
583		printf 'Run make\n'
584		printf '\n'
585		printf 'Then run %s/tests/randmath.py and the fuzzer.\n' "$scriptdir"
586		printf '\n'
587		printf 'Then run ASan on the fuzzer test cases with the following build:\n'
588		printf '\n'
589		printf '    CFLAGS="-fsanitize=address -fno-omit-frame-pointer -DBC_ENABLE_RAND=0" ./configure.sh -gO3 -HNPS\n'
590		printf '    make\n'
591		printf '\n'
592		printf 'Then run the GitHub release script as follows:\n'
593		printf '\n'
594		printf '    <github_release> <version> .gitignore .gitattributes\\\n'
595		printf '    manpage.sh release.sh RELEASE.md tests/afl.py\\\n'
596		printf '    tests/radamsa.sh tests/radamsa.txt tests/randmath.py\\\n'
597		printf '    tests/fuzzing/ tests/bc/scripts/timeconst.bc\n'
598
599	fi
600
601fi
602