diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e9b84e4..4e2ae3ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,8 +3,22 @@ name: Test on: [push, pull_request] jobs: + makefile-analysis: + name: makefile-analysis + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: "Install analysis tools" + run: | + sudo apt-get update + sudo apt-get install -y clang-tools valgrind + - name: Run tests + run: ./test/ci/analysis.sh + makefile-test: name: makefile-${{ matrix.runner }}-amd64-${{ matrix.compiler }} ${{ ((matrix.openmp == 1) && '+openmp') || '' }} + needs: makefile-analysis runs-on: ${{ matrix.runner }} strategy: fail-fast: false @@ -29,6 +43,7 @@ jobs: cmake-test: name: cmake-${{ matrix.runner }}-${{ matrix.platform }} + needs: makefile-analysis runs-on: ${{ matrix.runner }} strategy: fail-fast: false @@ -65,6 +80,7 @@ jobs: alpine-makefile-test: name: makefile-alpine-amd64-gcc + needs: makefile-analysis runs-on: ubuntu-latest container: image: alpine:3.12 @@ -80,6 +96,7 @@ jobs: alpine-cmake-test: name: cmake-alpine-amd64-gcc + needs: makefile-analysis runs-on: ubuntu-latest container: image: alpine:3.12 @@ -104,6 +121,7 @@ jobs: alpine-alt-arch-makefile-test: name: makefile-alpine-${{matrix.arch}}-${{matrix.cc}} + needs: makefile-analysis runs-on: ubuntu-latest strategy: fail-fast: false @@ -124,6 +142,7 @@ jobs: alpine-alt-arch-cmake-test: name: cmake-alpine-${{matrix.arch}}-${{matrix.cc}} + needs: makefile-analysis runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/test/Makefile b/test/Makefile index d1045824..c896627e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -11,12 +11,15 @@ else BENCH_LDFLAGS=-lrt endif -.PHONY: clean test +.PHONY: clean test valgrind test: clean test_base64 benchmark ./test_base64 ./benchmark +valgrind: clean test_base64 + valgrind --error-exitcode=2 ./test_base64 + test_base64: test_base64.c codec_supported.o ../lib/libbase64.o $(CC) $(CFLAGS) -o $@ $^ diff --git a/test/ci/analysis.sh b/test/ci/analysis.sh new file mode 100755 index 00000000..93ad8f64 --- /dev/null +++ b/test/ci/analysis.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -ve + +MACHINE=$(uname -m) +uname -a +clang --version # make analyse +${CC} --version # make -C test valgrind + +for USE_ASSEMBLY in 0 1; do + if [ "${MACHINE}" == "x86_64" ]; then + export SSSE3_CFLAGS="-mssse3 -DBASE64_SSSE3_USE_ASM=${USE_ASSEMBLY}" + export SSE41_CFLAGS="-msse4.1 -DBASE64_SSE41_USE_ASM=${USE_ASSEMBLY}" + export SSE42_CFLAGS="-msse4.2 -DBASE64_SSE42_USE_ASM=${USE_ASSEMBLY}" + export AVX_CFLAGS="-mavx -DBASE64_AVX_USE_ASM=${USE_ASSEMBLY}" + export AVX2_CFLAGS="-mavx2 -DBASE64_AVX2_USE_ASM=${USE_ASSEMBLY}" + # Temporarily disable AVX512; it is not available in CI yet. + # export AVX512_CFLAGS="-mavx512vl -mavx512vbmi" + elif [ "${MACHINE}" == "aarch64" ]; then + export NEON64_CFLAGS="-march=armv8-a" + elif [ "${MACHINE}" == "armv7l" ]; then + export NEON32_CFLAGS="-march=armv7-a -mfloat-abi=hard -mfpu=neon" + fi + + if [ ${USE_ASSEMBLY} -eq 0 ]; then + echo "::group::analyze" + make analyze + echo "::endgroup::" + fi + + echo "::group::valgrind (USE_ASSEMBLY=${USE_ASSEMBLY})" + make clean + make + make -C test valgrind + echo "::endgroup::" +done diff --git a/test/test_base64.c b/test/test_base64.c index ee8d7068..94aad2d4 100644 --- a/test/test_base64.c +++ b/test/test_base64.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "../include/libbase64.h" #include "codec_supported.h" #include "moby_dick.h" @@ -92,7 +93,7 @@ assert_roundtrip (int flags, const char *src) } static int -test_char_table (int flags) +test_char_table (int flags, bool use_malloc) { bool fail = false; char chr[256]; @@ -107,8 +108,24 @@ test_char_table (int flags) for (int i = 0; i < 256; i++) { size_t chrlen = 256 - i; + char* src = &chr[i]; + if (use_malloc) { + src = malloc(chrlen); /* malloc/copy this so valgrind can find out-of-bound access */ + if (src == NULL) { + printf( + "FAIL: encoding @ %d: allocation of %lu bytes failed\n", + i, (unsigned long)chrlen + ); + fail = true; + continue; + } + memcpy(src, &chr[i], chrlen); + } - base64_encode(&chr[i], chrlen, enc, &enclen, BASE64_FORCE_PLAIN); + base64_encode(src, chrlen, enc, &enclen, flags); + if (use_malloc) { + free(src); + } if (!base64_decode(enc, enclen, dec, &declen, flags)) { printf("FAIL: decoding @ %d: decoding error\n", i); @@ -341,7 +358,8 @@ test_one_codec (const char *codec, int flags) fail |= assert_roundtrip(flags, vec[i].out); } - fail |= test_char_table(flags); + fail |= test_char_table(flags, false); /* test with unaligned input buffer */ + fail |= test_char_table(flags, true); /* test for out-of-bound input read */ fail |= test_streaming(flags); fail |= test_invalid_dec_input(flags);