An implementation of Unix dc and POSIX bc with GNU and BSD extensions. Finished, but well-maintained.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

601 lines
13 KiB

2 years ago
2 years ago
  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. usage() {
  30. printf 'usage: %s [run_tests] [generate_tests] [test_with_clang] [test_with_gcc] \n' "$script"
  31. printf ' [run_sanitizers] [run_valgrind] [run_64_bit] [run_gen_script]\n'
  32. printf ' [test_c11] [test_128_bit]\n'
  33. exit 1
  34. }
  35. header() {
  36. _header_msg="$1"
  37. shift
  38. printf '\n'
  39. printf '*******************\n'
  40. printf "$_header_msg"
  41. printf '\n'
  42. printf '*******************\n'
  43. printf '\n'
  44. }
  45. do_make() {
  46. make -j16 "$@"
  47. }
  48. configure() {
  49. _configure_CFLAGS="$1"
  50. shift
  51. _configure_CC="$1"
  52. shift
  53. _configure_configure_flags="$1"
  54. shift
  55. _configure_GEN_HOST="$1"
  56. shift
  57. _configure_LONG_BIT="$1"
  58. shift
  59. if [ "$gen_tests" -eq 0 ]; then
  60. _configure_configure_flags="-G $_configure_configure_flags"
  61. fi
  62. if [ "$_configure_CC" = "clang" ]; then
  63. _configure_CFLAGS="$clang_flags $_configure_CFLAGS"
  64. elif [ "$_configure_CC" = "gcc" ]; then
  65. _configure_CFLAGS="$gcc_flags $_configure_CFLAGS"
  66. fi
  67. _configure_header=$(printf 'Running ./configure.sh %s ...' "$_configure_configure_flags")
  68. _configure_header=$(printf "$_configure_header\n CC=\"%s\"\n" "$_configure_CC")
  69. _configure_header=$(printf "$_configure_header\n CFLAGS=\"%s\"\n" "$_configure_CFLAGS")
  70. _configure_header=$(printf "$_configure_header\n LONG_BIT=%s" "$_configure_LONG_BIT")
  71. _configure_header=$(printf "$_configure_header\n GEN_HOST=%s" "$_configure_GEN_HOST")
  72. header "$_configure_header"
  73. CFLAGS="$_configure_CFLAGS" CC="$_configure_CC" GEN_HOST="$_configure_GEN_HOST" \
  74. LONG_BIT="$_configure_LONG_BIT" ./configure.sh $_configure_configure_flags > /dev/null
  75. }
  76. build() {
  77. _build_CFLAGS="$1"
  78. shift
  79. _build_CC="$1"
  80. shift
  81. _build_configure_flags="$1"
  82. shift
  83. _build_GEN_HOST="$1"
  84. shift
  85. _build_LONG_BIT="$1"
  86. shift
  87. configure "$_build_CFLAGS" "$_build_CC" "$_build_configure_flags" "$_build_GEN_HOST" "$_build_LONG_BIT"
  88. _build_header=$(printf 'Building...\n CC=%s' "$_build_CC")
  89. _build_header=$(printf "$_build_header\n CFLAGS=\"%s\"" "$_build_CFLAGS")
  90. _build_header=$(printf "$_build_header\n LONG_BIT=%s" "$_build_LONG_BIT")
  91. _build_header=$(printf "$_build_header\n GEN_HOST=%s" "$_build_GEN_HOST")
  92. header "$_build_header"
  93. do_make > /dev/null 2> "$scriptdir/.test.txt"
  94. if [ -s "$scriptdir/.test.txt" ]; then
  95. printf '%s generated warning(s):\n' "$_build_CC"
  96. printf '\n'
  97. cat "$scriptdir/.test.txt"
  98. exit 1
  99. fi
  100. }
  101. runtest() {
  102. header "Running tests"
  103. if [ "$#" -gt 0 ]; then
  104. do_make "$@"
  105. else
  106. do_make test
  107. fi
  108. }
  109. runconfigtests() {
  110. _runconfigtests_CFLAGS="$1"
  111. shift
  112. _runconfigtests_CC="$1"
  113. shift
  114. _runconfigtests_configure_flags="$1"
  115. shift
  116. _runconfigtests_GEN_HOST="$1"
  117. shift
  118. _runconfigtests_LONG_BIT="$1"
  119. shift
  120. _runconfigtests_run_tests="$1"
  121. shift
  122. if [ "$_runconfigtests_run_tests" -ne 0 ]; then
  123. _runconfigtests_header=$(printf 'Running tests with configure flags')
  124. else
  125. _runconfigtests_header=$(printf 'Building with configure flags')
  126. fi
  127. _runconfigtests_header=$(printf "$_runconfigtests_header \"%s\" ...\n" "$_runconfigtests_configure_flags")
  128. _runconfigtests_header=$(printf "$_runconfigtests_header\n CC=%s\n" "$_runconfigseries_CC")
  129. _runconfigtests_header=$(printf "$_runconfigtests_header\n CFLAGS=\"%s\"" "$_runconfigseries_CFLAGS")
  130. _runconfigtests_header=$(printf "$_runconfigtests_header\n LONG_BIT=%s" "$_runconfigtests_LONG_BIT")
  131. _runconfigtests_header=$(printf "$_runconfigtests_header\n GEN_HOST=%s" "$_runconfigtests_GEN_HOST")
  132. header "$_runconfigtests_header"
  133. build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \
  134. "$_runconfigtests_configure_flags" "$_runconfigtests_GEN_HOST" \
  135. "$_runconfigtests_LONG_BIT"
  136. if [ "$_runconfigtests_run_tests" -ne 0 ]; then
  137. runtest
  138. fi
  139. do_make clean
  140. build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \
  141. "$_runconfigtests_configure_flags -b" "$_runconfigtests_GEN_HOST" \
  142. "$_runconfigtests_LONG_BIT"
  143. if [ "$_runconfigtests_run_tests" -ne 0 ]; then
  144. runtest
  145. fi
  146. do_make clean
  147. build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \
  148. "$_runconfigtests_configure_flags -d" "$_runconfigtests_GEN_HOST" \
  149. "$_runconfigtests_LONG_BIT"
  150. if [ "$_runconfigtests_run_tests" -ne 0 ]; then
  151. runtest
  152. fi
  153. do_make clean
  154. }
  155. runconfigseries() {
  156. _runconfigseries_CFLAGS="$1"
  157. shift
  158. _runconfigseries_CC="$1"
  159. shift
  160. _runconfigseries_configure_flags="$1"
  161. shift
  162. _runconfigseries_run_tests="$1"
  163. shift
  164. if [ "$run_64_bit" -ne 0 ]; then
  165. if [ "$test_128_bit" -ne 0 ]; then
  166. runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
  167. "$_runconfigseries_configure_flags" 1 64 "$_runconfigseries_run_tests"
  168. fi
  169. if [ "$run_gen_script" -ne 0 ]; then
  170. runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
  171. "$_runconfigseries_configure_flags" 0 64 "$_runconfigseries_run_tests"
  172. fi
  173. runconfigtests "$_runconfigseries_CFLAGS -DBC_RAND_BUILTIN=0" "$_runconfigseries_CC" \
  174. "$_runconfigseries_configure_flags" 1 64 "$_runconfigseries_run_tests"
  175. fi
  176. runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
  177. "$_runconfigseries_configure_flags" 1 32 "$_runconfigseries_run_tests"
  178. if [ "$run_gen_script" -ne 0 ]; then
  179. runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \
  180. "$_runconfigseries_configure_flags" 0 32 "$_runconfigseries_run_tests"
  181. fi
  182. }
  183. runtestseries() {
  184. _runtestseries_CFLAGS="$1"
  185. shift
  186. _runtestseries_CC="$1"
  187. shift
  188. _runtestseries_configure_flags="$1"
  189. shift
  190. _runtestseries_run_tests="$1"
  191. shift
  192. _runtestseries_flags="E H N P EH EN EP HN HP NP EHN EHP ENP HNP EHNP"
  193. runconfigseries "$_runtestseries_CFLAGS" "$_runtestseries_CC" \
  194. "$_runtestseries_configure_flags" "$_runtestseries_run_tests"
  195. for f in $_runtestseries_flags; do
  196. runconfigseries "$_runtestseries_CFLAGS" "$_runtestseries_CC" \
  197. "$_runtestseries_configure_flags -$f" "$_runtestseries_run_tests"
  198. done
  199. }
  200. runlibtests() {
  201. _runlibtests_CFLAGS="$1"
  202. shift
  203. _runlibtests_CC="$1"
  204. shift
  205. _runlibtests_configure_flags="$1"
  206. shift
  207. _runlibtests_run_tests="$1"
  208. shift
  209. _runlibtests_configure_flags="$_runlibtests_configure_flags -a"
  210. build "$_runlibtests_CFLAGS" "$_runlibtests_CC" "$_runlibtests_configure_flags" 1 64
  211. if [ "$_runlibtests_run_tests" -ne 0 ]; then
  212. runtest
  213. fi
  214. build "$_runlibtests_CFLAGS" "$_runlibtests_CC" "$_runlibtests_configure_flags" 1 32
  215. if [ "$_runlibtests_run_tests" -ne 0 ]; then
  216. runtest
  217. fi
  218. }
  219. runtests() {
  220. _runtests_CFLAGS="$1"
  221. shift
  222. _runtests_CC="$1"
  223. shift
  224. _runtests_configure_flags="$1"
  225. shift
  226. _runtests_run_tests="$1"
  227. shift
  228. runtestseries "-std=c99 $_runtests_CFLAGS" "$_runtests_CC" "$_runtests_configure_flags" "$_runtests_run_tests"
  229. if [ "$test_c11" -ne 0 ]; then
  230. runtestseries "-std=c11 $_runtests_CFLAGS" "$_runtests_CC" "$_runtests_configure_flags" "$_runtests_run_tests"
  231. fi
  232. }
  233. karatsuba() {
  234. header "Running Karatsuba tests"
  235. do_make karatsuba_test
  236. }
  237. vg() {
  238. header "Running valgrind"
  239. if [ "$run_64_bit" -ne 0 ]; then
  240. _vg_bits=64
  241. else
  242. _vg_bits=32
  243. fi
  244. build "$debug" "gcc" "-O0 -gv" "1" "$_vg_bits"
  245. runtest test
  246. do_make clean_config
  247. build "$debug" "gcc" "-O0 -gvb" "1" "$_vg_bits"
  248. runtest test
  249. do_make clean_config
  250. build "$debug" "gcc" "-O0 -gvd" "1" "$_vg_bits"
  251. runtest test
  252. do_make clean_config
  253. }
  254. debug() {
  255. _debug_CC="$1"
  256. shift
  257. _debug_run_tests="$1"
  258. shift
  259. runtests "$debug" "$_debug_CC" "-g" "$_debug_run_tests"
  260. if [ "$_debug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
  261. runtests "$debug -fsanitize=undefined" "$_debug_CC" "-g" "$_debug_run_tests"
  262. fi
  263. runlibtests "$debug" "$_debug_CC" "-g" "$_debug_run_tests"
  264. if [ "$_debug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
  265. runlibtests "$debug -fsanitize=undefined" "$_debug_CC" "-g" "$_debug_run_tests"
  266. fi
  267. }
  268. release() {
  269. _release_CC="$1"
  270. shift
  271. _release_run_tests="$1"
  272. shift
  273. runtests "$release" "$_release_CC" "-O3" "$_release_run_tests"
  274. runlibtests "$release" "$_release_CC" "-O3" "$_release_run_tests"
  275. }
  276. reldebug() {
  277. _reldebug_CC="$1"
  278. shift
  279. _reldebug_run_tests="$1"
  280. shift
  281. runtests "$debug" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
  282. if [ "$_reldebug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
  283. runtests "$debug -fsanitize=address" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
  284. runtests "$debug -fsanitize=memory" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
  285. fi
  286. runlibtests "$debug" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
  287. if [ "$_reldebug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then
  288. runlibtests "$debug -fsanitize=address" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
  289. runlibtests "$debug -fsanitize=memory" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests"
  290. fi
  291. }
  292. minsize() {
  293. _minsize_CC="$1"
  294. shift
  295. _minsize_run_tests="$1"
  296. shift
  297. runtests "$release" "$_minsize_CC" "-Os" "$_minsize_run_tests"
  298. runlibtests "$release" "$_minsize_CC" "-Os" "$_minsize_run_tests"
  299. }
  300. build_set() {
  301. _build_set_CC="$1"
  302. shift
  303. _build_set_run_tests="$1"
  304. shift
  305. debug "$_build_set_CC" "$_build_set_run_tests"
  306. release "$_build_set_CC" "$_build_set_run_tests"
  307. reldebug "$_build_set_CC" "$_build_set_run_tests"
  308. minsize "$_build_set_CC" "$_build_set_run_tests"
  309. }
  310. clang_flags="-Weverything -Wno-padded -Wno-switch-enum -Wno-format-nonliteral"
  311. clang_flags="$clang_flags -Wno-cast-align -Wno-missing-noreturn -Wno-disabled-macro-expansion"
  312. clang_flags="$clang_flags -Wno-unreachable-code -Wno-unreachable-code-return"
  313. clang_flags="$clang_flags -Wno-implicit-fallthrough"
  314. gcc_flags="-Wno-maybe-uninitialized -Wno-clobbered"
  315. cflags="-Wall -Wextra -Werror -pedantic -Wno-conditional-uninitialized"
  316. debug="$cflags -fno-omit-frame-pointer"
  317. release="$cflags -DNDEBUG"
  318. set -e
  319. script="$0"
  320. scriptdir=$(dirname "$script")
  321. if [ "$#" -gt 0 ]; then
  322. run_tests="$1"
  323. shift
  324. else
  325. run_tests=1
  326. fi
  327. if [ "$#" -gt 0 ]; then
  328. gen_tests="$1"
  329. shift
  330. else
  331. gen_tests=1
  332. fi
  333. if [ "$#" -gt 0 ]; then
  334. test_with_clang="$1"
  335. shift
  336. else
  337. test_with_clang=1
  338. fi
  339. if [ "$#" -gt 0 ]; then
  340. test_with_gcc="$1"
  341. shift
  342. else
  343. test_with_gcc=1
  344. fi
  345. if [ "$#" -gt 0 ]; then
  346. run_sanitizers="$1"
  347. shift
  348. else
  349. run_sanitizers=1
  350. fi
  351. if [ "$#" -gt 0 ]; then
  352. run_valgrind="$1"
  353. shift
  354. else
  355. run_valgrind=1
  356. fi
  357. if [ "$#" -gt 0 ]; then
  358. run_64_bit="$1"
  359. shift
  360. else
  361. run_64_bit=1
  362. fi
  363. if [ "$#" -gt 0 ]; then
  364. run_gen_script="$1"
  365. shift
  366. else
  367. run_gen_script=0
  368. fi
  369. if [ "$#" -gt 0 ]; then
  370. test_c11="$1"
  371. shift
  372. else
  373. test_c11=0
  374. fi
  375. if [ "$#" -gt 0 ]; then
  376. test_128_bit="$1"
  377. shift
  378. else
  379. test_128_bit=0
  380. fi
  381. if [ "$run_64_bit" -ne 0 ]; then
  382. bits=64
  383. else
  384. bits=32
  385. fi
  386. cd "$scriptdir"
  387. if [ "$test_with_clang" -ne 0 ]; then
  388. defcc="clang"
  389. elif [ "$test_with_gcc" -ne 0 ]; then
  390. defcc="gcc"
  391. else
  392. defcc="c99"
  393. fi
  394. export ASAN_OPTIONS="abort_on_error=1,allocator_may_return_null=1"
  395. export UBSAN_OPTIONS="print_stack_trace=1,silence_unsigned_overflow=1"
  396. build "$debug" "$defcc" "-g" "1" "$bits"
  397. header "Running math library under --standard"
  398. printf 'quit\n' | bin/bc -ls
  399. do_make clean_tests
  400. if [ "$test_with_clang" -ne 0 ]; then
  401. build_set "clang" "$run_tests"
  402. fi
  403. if [ "$test_with_gcc" -ne 0 ]; then
  404. build_set "gcc" "$run_tests"
  405. fi
  406. if [ "$run_tests" -ne 0 ]; then
  407. build "$release" "$defcc" "-O3" "1" "$bits"
  408. karatsuba
  409. if [ "$run_valgrind" -ne 0 -a "$test_with_gcc" -ne 0 ]; then
  410. vg
  411. fi
  412. printf '\n'
  413. printf 'Tests successful.\n'
  414. set +e
  415. command -v afl-gcc > /dev/null 2>&1
  416. err="$?"
  417. set -e
  418. if [ "$err" -eq 0 ]; then
  419. header "Configuring for afl-gcc..."
  420. configure "$debug $gcc_flags -DBC_ENABLE_RAND=0" "afl-gcc" "-HNP -gO3" "1" "$bits"
  421. printf '\n'
  422. printf 'Run make\n'
  423. printf '\n'
  424. printf 'Then run %s/tests/randmath.py and the fuzzer.\n' "$scriptdir"
  425. printf '\n'
  426. printf 'Then run ASan on the fuzzer test cases with the following build:\n'
  427. printf '\n'
  428. printf ' CFLAGS="-fsanitize=address -fno-omit-frame-pointer -DBC_ENABLE_RAND=0" ./configure.sh -gO3 -HNPS\n'
  429. printf ' make\n'
  430. printf '\n'
  431. printf 'Then run the GitHub release script as follows:\n'
  432. printf '\n'
  433. printf ' <github_release> <version> .gitignore .gitattributes\\\n'
  434. printf ' manpage.sh release.sh RELEASE.md tests/afl.py\\\n'
  435. printf ' tests/radamsa.sh tests/radamsa.txt tests/randmath.py\\\n'
  436. printf ' tests/fuzzing/ tests/bc/scripts/timeconst.bc\n'
  437. fi
  438. fi