blob: 4060c09a4194220c7ef1de55f8d1f79a73bca5bd [file]
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
set -e
# Parse arguments. --no-instrument performs code generation and builds the
# 12 fuzzer assemblies but skips SharpFuzz IL rewriting. Intended for
# `make check`, where we want to catch source changes that break the
# fuzzer build without requiring the dev-only SharpFuzz.CommandLine
# global tool or the libfuzzer-dotnet native driver.
INSTRUMENT=1
for arg in "$@"; do
case "$arg" in
--no-instrument)
INSTRUMENT=0
;;
*)
echo "Unknown argument: $arg"
echo "Usage: $0 [--no-instrument]"
exit 1
;;
esac
done
# Ensure the SharpFuzz.CommandLine global tool (runtimeconfig-pinned to
# net9.0 in package 2.2.0) can roll forward onto the net10 runtime used
# by this repo. Remove once SharpFuzz 2.3.0 (upstream PR #72) ships with
# an updated runtimeconfig.
export DOTNET_ROLL_FORWARD=Major
if [ "$INSTRUMENT" = "1" ]; then
# Check for SHARPFUZZ_DIR environment variable
if [ -z "$SHARPFUZZ_DIR" ]; then
echo "Error: SHARPFUZZ_DIR environment variable is not set."
echo "Please set SHARPFUZZ_DIR to the location of your SharpFuzz installation."
echo "See README for installation instructions."
exit 1
fi
# Verify libfuzzer-dotnet exists
LIBFUZZER="$SHARPFUZZ_DIR/libfuzzer-dotnet"
if [ ! -f "$LIBFUZZER" ]; then
echo "Error: libfuzzer-dotnet not found at $LIBFUZZER"
echo "Please ensure SharpFuzz is properly installed in $SHARPFUZZ_DIR"
echo "See README for installation instructions."
exit 1
fi
# Verify the sharpfuzz instrumentation CLI is on PATH before we spend
# time building 12 assemblies that would otherwise fail to be instrumented.
if ! command -v sharpfuzz >/dev/null 2>&1; then
echo "Error: 'sharpfuzz' CLI not found on PATH."
echo "Install it with:"
echo " dotnet tool install --global SharpFuzz.CommandLine"
echo " export PATH=\"\$PATH:\$HOME/.dotnet/tools\""
echo "See README for full installation instructions."
exit 1
fi
fi
# Find the local Thrift compiler
THRIFT="$(dirname "$0")/../../compiler/cpp/thrift"
THRIFT=$(realpath "$THRIFT")
# Paths — resolved to absolute so they survive the cd below
THRIFT_FILE=$(realpath "$(dirname "$0")/../../test/FuzzTest.thrift")
GEN_DIR=$(realpath -m "$(dirname "$0")/Tests/Thrift.FuzzTests/gen-netstd")
FUZZERS_DIR=$(realpath "$(dirname "$0")/Tests/Thrift.FuzzTests")
OUTPUT_DIR="$FUZZERS_DIR/bin/Debug/net10.0"
# Step 1: Generate C# code from FuzzTest.thrift
if [ ! -x "$THRIFT" ]; then
echo "Error: Thrift compiler not found at $THRIFT"
exit 1
fi
# Clean and create the generated directory
rm -rf "$GEN_DIR"
mkdir -p "$GEN_DIR"
echo "[1/13] Generating C# code from $THRIFT_FILE ..."
"$THRIFT" --gen netstd:net10 -out "$GEN_DIR" "$THRIFT_FILE"
echo "C# code generated in $GEN_DIR."
# Step 2: Build all fuzzer projects
cd "$(dirname "$0")"
# Build all fuzzer combinations using the consolidated project
BUILD_COUNT=2
for protocol in Binary Compact Json; do
for fuzzer_type_raw in Parse Roundtrip; do
for engine in AFL Libfuzzer; do
# Construct display name
if [ "$fuzzer_type_raw" = "Parse" ]; then
display_name="$protocol Protocol $engine"
fuzzer_type=""
else
display_name="$protocol Protocol round-trip $engine"
fuzzer_type="Roundtrip"
fi
echo "[$BUILD_COUNT/13] Building $display_name ..."
dotnet build "$FUZZERS_DIR/Thrift.FuzzTests.csproj" \
-p:Protocol=$protocol \
-p:FuzzerType=$fuzzer_type_raw \
-p:Engine=$engine
BUILD_COUNT=$((BUILD_COUNT + 1))
done
done
done
# Step 3: Instrument the assemblies
if [ "$INSTRUMENT" = "0" ]; then
echo "Build complete (instrumentation skipped)."
exit 0
fi
echo "Instrumenting assemblies for fuzzing ..."
# Exclusions for instrumentation
EXCLUSIONS=("dnlib.dll" "SharpFuzz.dll" "SharpFuzz.Common.dll")
# Find and instrument fuzzing targets
while IFS= read -r -d '' dll; do
dll_name=$(basename "$dll")
skip=false
for excl in "${EXCLUSIONS[@]}"; do
if [[ "$dll_name" == "$excl" ]]; then
skip=true
break
fi
done
if [[ "$dll_name" == System.*.dll ]]; then
skip=true
fi
if [[ "$dll_name" == Thrift.FuzzTests.*.dll ]]; then
skip=true # Skip the fuzzer assemblies themselves
fi
if [ "$skip" = true ]; then
echo "Skipping $dll_name"
continue
fi
if [ "$skip" = false ]; then
echo "Instrumenting $dll_name"
sharpfuzz "$dll"
if [ $? -ne 0 ]; then
echo "An error occurred while instrumenting $dll"
exit 1
fi
fi
done < <(find "$OUTPUT_DIR" -maxdepth 1 -type f -name "*.dll" -print0)
echo "Build and instrumentation complete."