Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: run fuzz tests in parallel and generate coverage report #4960

Merged
merged 12 commits into from
Dec 23, 2024
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ if (COVERAGE)
# on LLVM compilers. GCC would fail with "unrecognized compile options"
# on -fprofile-instr-generate -fcoverage-mapping flags.
if (NOT ${CMAKE_C_COMPILER_ID} MATCHES Clang)
message(FATAL_ERROR "This project requires clang for coverage support")
message(FATAL_ERROR "This project requires clang for coverage support. You are currently using " ${CMAKE_C_COMPILER_ID})
endif()
target_compile_options(${PROJECT_NAME} PUBLIC -fprofile-instr-generate -fcoverage-mapping)
target_link_options(${PROJECT_NAME} PUBLIC -fprofile-instr-generate -fcoverage-mapping)
Expand Down Expand Up @@ -696,6 +696,12 @@ if (BUILD_TESTING)
set(ARTIFACT_UPLOAD_LOC "none")
endif()

if(COVERAGE)
set(FUZZ_COVERAGE "true")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that we can't just use COVERAGE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I can just use COVERAGE 😓. Thank you for pointing it out

else()
set(FUZZ_COVERAGE "false")
endif()

# Build LD_PRELOAD shared libraries
file(GLOB LIBRARY_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/tests/fuzz/LD_PRELOAD/*.c")
foreach(SRC ${LIBRARY_SRCS})
Expand Down Expand Up @@ -732,6 +738,8 @@ if (BUILD_TESTING)
${BUILD_DIR_PATH}
${CORPUS_UPLOAD_LOC}
${ARTIFACT_UPLOAD_LOC}
${FUZZ_COVERAGE}
${CMAKE_CURRENT_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/fuzz
)
set_property(TEST ${TEST_NAME} PROPERTY LABELS "fuzz")
Expand Down
2 changes: 1 addition & 1 deletion codebuild/spec/buildspec_fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ phases:
on-failure: ABORT
commands:
# -L: Restrict tests to names matching the pattern 'fuzz'
- cmake --build build/ --target test -- ARGS="-L fuzz --output-on-failure"
- cmake --build build/ --target test -- ARGS="-L fuzz --output-on-failure -j $(nproc)"
68 changes: 16 additions & 52 deletions codebuild/spec/buildspec_fuzz_scheduled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,11 @@
# limitations under the License.
version: 0.2

batch:
build-matrix:
static:
env:
privileged-mode: true
dynamic:
env:
compute-type:
- BUILD_GENERAL1_LARGE
image:
- 024603541914.dkr.ecr.us-west-2.amazonaws.com/docker:ubuntu22codebuild
privileged-mode: true
variables:
S2N_LIBCRYPTO:
- awslc
FUZZ_TESTS:
- "s2n_cert_req_recv_test"
- "s2n_certificate_extensions_parse_test"
- "s2n_client_ccs_recv_test"
- "s2n_client_cert_recv_test"
- "s2n_client_cert_verify_recv_test"
- "s2n_client_finished_recv_test"
- "s2n_client_fuzz_test"
- "s2n_client_hello_recv_fuzz_test"
- "s2n_client_key_recv_fuzz_test"
- "s2n_deserialize_resumption_state_test"
- "s2n_encrypted_extensions_recv_test"
- "s2n_extensions_client_key_share_recv_test"
- "s2n_extensions_client_supported_versions_recv_test"
- "s2n_extensions_server_key_share_recv_test"
- "s2n_extensions_server_supported_versions_recv_test"
- "s2n_hybrid_ecdhe_kyber_r3_fuzz_test"
- "s2n_kyber_r3_recv_ciphertext_fuzz_test"
- "s2n_kyber_r3_recv_public_key_fuzz_test"
- "s2n_memory_leak_negative_test"
- "s2n_openssl_diff_pem_parsing_test"
- "s2n_recv_client_supported_groups_test"
- "s2n_select_server_cert_test"
- "s2n_server_ccs_recv_test"
- "s2n_server_cert_recv_test"
- "s2n_server_extensions_recv_test"
- "s2n_server_finished_recv_test"
- "s2n_server_fuzz_test"
- "s2n_server_hello_recv_test"
- "s2n_stuffer_pem_fuzz_test"
- "s2n_tls13_cert_req_recv_test"
- "s2n_tls13_cert_verify_recv_test"
- "s2n_tls13_client_finished_recv_test"
- "s2n_tls13_server_finished_recv_test"
env:
variables:
CC: "/usr/bin/clang"
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
CXX: "/usr/bin/clang++"
S2N_LIBCRYPTO: "awslc"

phases:
pre_build:
Expand All @@ -77,12 +33,20 @@ phases:
cmake . -Bbuild \
-DCMAKE_PREFIX_PATH=/usr/local/$S2N_LIBCRYPTO \
-DS2N_FUZZ_TEST=on \
-DFUZZ_TIMEOUT_SEC=27000
-DFUZZ_TIMEOUT_SEC=27000 \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this an environment variable makes it easy to over-ride later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I had to make changes to this line to test for shorter duration. Will change this to an env var

-DCOVERAGE=on \
-DBUILD_SHARED_LIBS=ON
- cmake --build ./build -- -j $(nproc)
post_build:
on-failure: ABORT
commands:
# -L: Restrict tests to labels matching the pattern 'fuzz'
# -R: Run the single fuzz test defined in ${FUZZ_TESTS}
# --timeout: override ctest's default timeout of 1500
- cmake --build build/ --target test -- ARGS="-L fuzz -R ${FUZZ_TESTS} --output-on-failure --timeout 28800"
- cmake --build build/ --target test -- ARGS="-L fuzz --output-on-failure -j $(nproc) --timeout 28800"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above; if timeout is an env. var we can over-ride it later

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I suspect we won't be running fuzz tests for more than 28800 secs though. I'm also not exactly sure how I make this into env, probably something like this?

cmake --build build/ --target test -- ARGS="-L fuzz --output-on-failure -j $(nproc) --timeout $TIMEOUT_VALUE"

- ./tests/fuzz/calcTotalCov.sh

artifacts:
# upload all files in the fuzz_coverage_report directory
files:
- '**/*'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broad file mask should keep this from failing, but have you tested the use of artifact uploads? (they have been flaky).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wildcard match looks a little bit suspicious to me. Won't this upload everything? I'd expect the pattern to be something more like fuzz_coverage_report/*.

Copy link
Contributor Author

@jouho jouho Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

**/* means all files recursively, from the base-directory which is currently set to fuzz_coverage_report.
The generated report contains many nested folders so we want to make sure to include those.

documentation: https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#:~:text=artifacts/base%2Ddirectory

Alternatively I could probably just specify fuzz_coverage_report/**/* without the base-directory option, but wanted to keep consistency with how mainline coverage specifies it:

artifacts:
# upload all files in the coverage_report directory
files:
- '**/*'
base-directory: coverage_report

Either way, I will test this to confirm the behavior, and paste the result.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I just missed the "base-directory" field 🤦

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested uploading coverage files to S3 bucket and is working. I uploaded a folder test-fuzz-coverage to s2n-build-artifacts bucket and you should be able to see the report there

base-directory: fuzz_coverage_report
41 changes: 14 additions & 27 deletions tests/fuzz/calcTotalCov.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,23 @@ if [ "$#" -ne "0" ]; then
usage
fi

if [[ -z "$S2N_ROOT" ]]; then
S2N_ROOT=../..
fi

FUZZCOV_SOURCES="${S2N_ROOT}/api ${S2N_ROOT}/bin ${S2N_ROOT}/crypto ${S2N_ROOT}/error ${S2N_ROOT}/stuffer ${S2N_ROOT}/tls ${S2N_ROOT}/utils"
FUZZCOV_SOURCES="api bin crypto error stuffer tls utils"

printf "Calculating total s2n coverage... \n"

# Outputs fuzz coverage results if the FUZZ_COVERAGE environment variable is set
# Total coverage is overlayed on source code in s2n_cov.html and coverage statistics are available in s2n_cov.txt
# If using LLVM version 9 or greater, coverage is output in LCOV format instead of HTML
# All files are stored in the s2n coverage directory
if [[ "$FUZZ_COVERAGE" == "true" ]]; then
# The llvm-profdata merge command warns that the profraws were created from different binaries (which is true) but
# works fine for what we care about (the s2n library). Therefore, for user clarity all output is suppressed.
llvm-profdata merge -sparse tests/fuzz/profiles/*/*.profdata -o tests/fuzz/profiles/merged_fuzz.profdata > /dev/null 2>&1

printf "Calculating total s2n coverage... "
llvm-cov report -instr-profile=tests/fuzz/profiles/merged_fuzz.profdata build/lib/libs2n.so ${FUZZCOV_SOURCES} > s2n_fuzz_coverage.txt

# The llvm-profdata merge command warns that the profraws were created from different binaries (which is true) but
# works fine for what we care about (the s2n library). Therefore, for user clarity all output is suppressed.
llvm-profdata merge -sparse ./profiles/*/*.profdata -o ./profiles/s2n_cov.profdata > /dev/null 2>&1
llvm-cov report -instr-profile=./profiles/s2n_cov.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} > ${COVERAGE_DIR}/fuzz/s2n_cov.txt
# convert coverage information to html format
llvm-cov export -instr-profile=tests/fuzz/profiles/merged_fuzz.profdata build/lib/libs2n.so ${FUZZCOV_SOURCES} -format=lcov > s2n_fuzz_cov.info

# Use LCOV format instead of HTML if the LLVM version we're using supports it
if [[ $(grep -Eo "[0-9]*" <<< `llvm-cov --version` | head -1) > 8 ]]; then
llvm-cov export -instr-profile=./profiles/s2n_cov.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} -format=lcov > ${COVERAGE_DIR}/fuzz/s2n_cov.info
genhtml -q -o ${COVERAGE_DIR}/html/overall_fuzz_coverage ${COVERAGE_DIR}/fuzz/s2n_cov.info
else
llvm-cov show -instr-profile=./profiles/s2n_cov.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} -use-color -format=html > ${COVERAGE_DIR}/fuzz/s2n_cov.html
fi
# Generate coverage report compatible with codecov.io
llvm-cov show -instr-profile=./profiles/s2n_cov.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} > ${COVERAGE_DIR}/fuzz/codecov.txt
genhtml s2n_fuzz_cov.info --branch-coverage -q -o fuzz_coverage_report

S2N_COV=`grep -Eo '[0-9]*\.[0-9]*\%' ${COVERAGE_DIR}/fuzz/s2n_cov.txt | tail -1`
printf "total s2n coverage from fuzz tests: %s\n" $S2N_COV
fi
S2N_COV=`grep -Eo '[0-9]*\.[0-9]*\%' s2n_fuzz_coverage.txt | tail -3`
LINE_COV=$(echo $S2N_COV | cut -d' ' -f1)
FUNC_COV=$(echo $S2N_COV | cut -d' ' -f2)
BRANCH_COV=$(echo $S2N_COV | cut -d' ' -f3)
printf "Coverage Report:\nLine coverage: %s\nFunction coverage: %s\nBranch coverage: %s\n" "$LINE_COV" "$FUNC_COV" "$BRANCH_COV"
Copy link
Contributor

@maddeleine maddeleine Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These numbers are fuzz coverage for the entire repo(I assume). However, we don't fuzz test the entire repo. I would look for a more meaningful metric, like coverage of a single fuzz tested function. Otherwise it's probably better to leave this out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is the coverage stats for the entire repo.

Hmm yeah the numbers themselves are probably not very valuable without being able to see the details. I can remove this from the output. We will have access to these numbers from the report anyways.

For getting coverage of a single fuzz tested function, I'm not too sure how it will look like, but my guess is that each fuzz test has its own targeted functions (for example, s2n_deserialize_resumption_state_test is targeting s2n_deserialize_resumption_state) and we want to see how much of the targeted functions are covered by that test.

I'm afraid adding that might complicate this PR, so I will have a follow-up PR after this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created an issue for this: #4966

24 changes: 14 additions & 10 deletions tests/fuzz/runFuzzTest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
set -e

usage() {
echo "Usage: runFuzzTest.sh TEST_NAME FUZZ_TIMEOUT_SEC"
echo "Usage: runFuzzTest.sh TEST_NAME FUZZ_TIMEOUT_SEC BUILD_DIR_PATH CORPUS_UPLOAD_LOC ARTIFACT_UPLOAD_LOC FUZZ_COVERAGE"
exit 1
}

if [ "$#" -ne "5" ]; then
if [ "$#" -ne "7" ]; then
usage
fi

Expand All @@ -31,6 +31,9 @@ FUZZ_TIMEOUT_SEC=$2
BUILD_DIR_PATH=$3
CORPUS_UPLOAD_LOC=$4
ARTIFACT_UPLOAD_LOC=$5
FUZZ_COVERAGE=$6
S2N_ROOT=$7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you using this variable anywhere? It's sort of a historical holddover from the Makefiles... and between CodeBuild and CMake, there should be existing equivalents defined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya, 7 CLI arguments is a lot, and I worry about the maintainability of this.

How can we make things simpler?

1 - Remove Unnecessary Options

My understanding is that right now BUILDER_DIR_PATH, CORPUS_UPLOAD_LOC, and ARTIFACT_UPLOAD_LOC are never actually set to anything else. And I'd imagine that if they were set to something else, a whole host of things would break. That's a good sign that these aren't actually configurable, and are probably better off being represented as constant values.

2 - Separation of Concerns

Generally it's best to "separate concerns". Don't unnecessarily couple things that don't need to be coupled. This applies to shell scripts that same way that it applies to actual code

// tricky and complex, probably not the best option
fn run_fuzz_tests_and_generate_coverage_report(arg1, arg2, arg3, arg4, arg5, arg6, arg6)

// a bit more manageable
fn run_fuzz_tests(arg1, arg2, arg3, arg4)
fn generate_coverage_report(arg5, arg6, arg7)

I'd imagine an ideal "coverage pipeline" to look something like this

  1. build the fuzz test binaries with instrumentation enabled
  2. download the corpus files
  3. run the fuzz tests (which is mostly agnostic as to whether or not coverage is enabled)
  4. upload the improved corpus files
  5. merge the coverage information/generate the report
  6. upload the report

It seems odd that all of the coverage reporting is living inside a script called runFuzzTests. Perhaps we could refactor coverage_report.sh to be slightly more generic, and then everything could use the same script?

3 - Scrutinize Coverage Assertions

I like the idea of asserting on some sort of coverage information. "feature coverage" from the fuzzer seems very nice and easy to assert on.

Asserting on coverage from the actual report seems to requires a big blob of sed/grep/regex all squished together, and that is not sparking joy.

What benefit does this complicated stuff provide that feature coverage doesn't? And are our thresholds/assertions well-researched enough to actually be useful? I know we found that session ticket coverage issue when manually reviewing the code, so I question the value of these more complex assertions.

Copy link
Contributor Author

@jouho jouho Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I should be able to remove BUILD_DIR_PATH and just give a hardcoded path to the build directory.

But CORPUS_UPLOAD_LOC, and ARTIFACT_UPLOAD_LOC, are s3 bucket locations (For example, "s3:://bucketName"). There is probably no security concerns to make it public, as it requires correct IAM roles to be able to access the bucket. Is it fine making such resource info into hard-coded const?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some refactoring so it only takes 3 CLI arguments instead of 7.

Since runFuzzTest.sh is very large and hard to read, I have broken it into smaller components which are:

runFuzzTest.sh: responsible for running the actual fuzz test
fuzz_corpus_download.sh: responsible for downloading corpus files from S3
fuzz_corpus_upload.sh: responsible for uploading improved corpus files to S3
fuzz_coverage_report.sh: responsible for generating coverage information

On top of that, I removed couple of print statements that were hidden by CTest. I left the outputs that are useful for debugging in case fuzzing fails.


MIN_TEST_PER_SEC="1000"
MIN_FEATURES_COVERED="100"

Expand All @@ -46,7 +49,7 @@ ASAN_OPTIONS+="symbolize=1"
LSAN_OPTIONS+="log_threads=1"
UBSAN_OPTIONS+="print_stacktrace=1"
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
NUM_CPU_THREADS=$(nproc)
LIBFUZZER_ARGS+="-timeout=5 -max_len=4096 -print_final_stats=1 -jobs=${NUM_CPU_THREADS} -workers=${NUM_CPU_THREADS} -max_total_time=${FUZZ_TIMEOUT_SEC}"
LIBFUZZER_ARGS+="-timeout=5 -max_len=4096 -print_final_stats=1 -workers=${NUM_CPU_THREADS} -max_total_time=${FUZZ_TIMEOUT_SEC}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LIBFUZZER_ARGS+="-timeout=5 -max_len=4096 -print_final_stats=1 -workers=${NUM_CPU_THREADS} -max_total_time=${FUZZ_TIMEOUT_SEC}"
LIBFUZZER_ARGS+="-timeout=5 -max_len=4096 -print_final_stats=1 -max_total_time=${FUZZ_TIMEOUT_SEC}"

The workers arg should not longer be needed (because everything is single threaded/run on a single core).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this in the latest commit


TEST_SPECIFIC_OVERRIDES="${BUILD_DIR_PATH}/lib/lib${TEST_NAME}_overrides.so"
GLOBAL_OVERRIDES="${BUILD_DIR_PATH}/lib/libglobal_overrides.so"
Expand Down Expand Up @@ -106,6 +109,7 @@ if [[ "$FUZZ_COVERAGE" == "true" ]]; then
mkdir -p "./profiles/${TEST_NAME}"
rm -f ./profiles/${TEST_NAME}/*.profraw
LLVM_PROFILE_FILE="./profiles/${TEST_NAME}/${TEST_NAME}.%p.profraw" \
env LD_PRELOAD="$LD_PRELOAD_" \
${BUILD_DIR_PATH}/bin/${TEST_NAME} ${LIBFUZZER_ARGS} ${TEMP_CORPUS_DIR} \
> ${TEST_NAME}_output.txt 2>&1 || ACTUAL_TEST_FAILURE=1
else
Expand All @@ -129,16 +133,16 @@ declare -i TARGET_COV=0
# If using LLVM version 9 or greater, coverage is output in LCOV format instead of HTML
# All files are stored in the s2n coverage directory
if [[ "$FUZZ_COVERAGE" == "true" ]]; then
mkdir -p ${COVERAGE_DIR}/fuzz
mkdir -p coverage/fuzz
llvm-profdata merge -sparse ./profiles/${TEST_NAME}/*.profraw -o ./profiles/${TEST_NAME}/${TEST_NAME}.profdata
llvm-cov report -instr-profile=./profiles/${TEST_NAME}/${TEST_NAME}.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} -show-functions > ${COVERAGE_DIR}/fuzz/${TEST_NAME}_cov.txt
llvm-cov report -instr-profile=./profiles/${TEST_NAME}/${TEST_NAME}.profdata ${BUILD_DIR_PATH}/lib/libs2n.so ${FUZZCOV_SOURCES} -show-functions > coverage/fuzz/${TEST_NAME}_cov.txt

# Use LCOV format instead of HTML if the LLVM version we're using supports it
if [[ $(grep -Eo "[0-9]*" <<< `llvm-cov --version` | head -1) -gt 8 ]]; then
llvm-cov export -instr-profile=./profiles/${TEST_NAME}/${TEST_NAME}.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} -format=lcov > ${COVERAGE_DIR}/fuzz/${TEST_NAME}_cov.info
genhtml -q -o ${COVERAGE_DIR}/html/${TEST_NAME} ${COVERAGE_DIR}/fuzz/${TEST_NAME}_cov.info
llvm-cov export -instr-profile=./profiles/${TEST_NAME}/${TEST_NAME}.profdata ${BUILD_DIR_PATH}/lib/libs2n.so ${FUZZCOV_SOURCES} -format=lcov > coverage/fuzz/${TEST_NAME}_cov.info
genhtml -q -o coverage/html/${TEST_NAME} coverage/fuzz/${TEST_NAME}_cov.info
else
llvm-cov show -instr-profile=./profiles/${TEST_NAME}/${TEST_NAME}.profdata ${S2N_ROOT}/lib/libs2n.so ${FUZZCOV_SOURCES} -use-color -format=html > ${COVERAGE_DIR}/fuzz/${TEST_NAME}_cov.html
llvm-cov show -instr-profile=./profiles/${TEST_NAME}/${TEST_NAME}.profdata ${BUILD_DIR_PATH}/lib/libs2n.so ${FUZZCOV_SOURCES} -use-color -format=html > coverage/fuzz/${TEST_NAME}_cov.html
fi

# Extract target functions from test source
Expand All @@ -149,8 +153,8 @@ if [[ "$FUZZ_COVERAGE" == "true" ]]; then
then
for TARGET in ${TARGET_FUNCS}
do
TARGET_TOTAL+=`sed -n "s/^.*${TARGET} .*% *\([0-9]*\) .*$/\1/p" ${COVERAGE_DIR}/fuzz/${TEST_NAME}_cov.txt`
TARGET_COV+=`sed -n "s/^.*${TARGET} .*% *[0-9]* *\([0-9]*\) .*$/\1/p" ${COVERAGE_DIR}/fuzz/${TEST_NAME}_cov.txt`
TARGET_TOTAL+=`sed -n "s/^.*${TARGET} .*% *\([0-9]*\) .*$/\1/p" coverage/fuzz/${TEST_NAME}_cov.txt`
TARGET_COV+=`sed -n "s/^.*${TARGET} .*% *[0-9]* *\([0-9]*\) .*$/\1/p" coverage/fuzz/${TEST_NAME}_cov.txt`
done
fi
fi
Expand Down
Loading