Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions lib/netstd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,26 @@ SUBDIRS = .
all-local:
$(DOTNETCORE) build -c Release

check-local:
check-local: precompile-fuzzers
$(DOTNETCORE) test Tests/Thrift.Compile.Tests/Thrift.Compile.net8/Thrift.Compile.net8.csproj
$(DOTNETCORE) test Tests/Thrift.Compile.Tests/Thrift.Compile.net9/Thrift.Compile.net9.csproj
$(DOTNETCORE) test Tests/Thrift.Compile.Tests/Thrift.Compile.netstd2/Thrift.Compile.netstd2.csproj
$(DOTNETCORE) test Tests/Thrift.Tests/Thrift.Tests.csproj
$(DOTNETCORE) test Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj

# Opt-in. Not wired into check-local because it requires the
# SharpFuzz.CommandLine global tool and libfuzzer-dotnet binary,
# which are dev-only dependencies. Run manually: `make build-fuzzers`.
# Compile-only build of the 12 fuzzer variants, without SharpFuzz
# IL rewriting. Wired into check-local so CI catches source changes
# that would break the fuzzer build — the actual fuzzing tooling
# (SharpFuzz.CommandLine global tool, libfuzzer-dotnet) is a dev-only
# dependency not present in CI.
precompile-fuzzers:
./buildfuzzers.sh --no-instrument

# Opt-in full build: compiles and instruments the 12 fuzzer variants
# for actual fuzzing. Requires the SharpFuzz.CommandLine global tool
# and libfuzzer-dotnet binary. Run manually: `make build-fuzzers`.
build-fuzzers:
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Binary -p:FuzzerType=Parse -p:Engine=AFL
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Binary -p:FuzzerType=Parse -p:Engine=Libfuzzer
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Binary -p:FuzzerType=Roundtrip -p:Engine=AFL
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Binary -p:FuzzerType=Roundtrip -p:Engine=Libfuzzer
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Compact -p:FuzzerType=Parse -p:Engine=AFL
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Compact -p:FuzzerType=Parse -p:Engine=Libfuzzer
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Compact -p:FuzzerType=Roundtrip -p:Engine=AFL
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Compact -p:FuzzerType=Roundtrip -p:Engine=Libfuzzer
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Json -p:FuzzerType=Parse -p:Engine=AFL
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Json -p:FuzzerType=Parse -p:Engine=Libfuzzer
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Json -p:FuzzerType=Roundtrip -p:Engine=AFL
$(DOTNETCORE) build Tests/Thrift.FuzzTests/Thrift.FuzzTests.csproj -p:Protocol=Json -p:FuzzerType=Roundtrip -p:Engine=Libfuzzer
./buildfuzzers.sh

clean-local:
$(RM) -r Thrift/bin
Expand All @@ -63,6 +60,7 @@ clean-local:
$(RM) -r Tests/Thrift.Compile.Tests/Thrift.Compile.netstd2/obj
$(RM) -r Tests/Thrift.FuzzTests/bin
$(RM) -r Tests/Thrift.FuzzTests/obj
$(RM) -r Tests/Thrift.FuzzTests/gen-netstd

distdir:
$(MAKE) $(AM_MAKEFLAGS) distdir-am
Expand Down Expand Up @@ -102,5 +100,7 @@ EXTRA_DIST = \
Thrift.sln \
build.cmd \
build.sh \
buildfuzzers.sh \
runfuzzer.sh \
runtests.cmd \
runtests.sh
9 changes: 8 additions & 1 deletion lib/netstd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ Because of the different environment requirements, migration from C# takes sligh

# Fuzzing

We use [SharpFuzz](https://github.com/Metalnem/sharpfuzz) (and its libfuzzer variant) to fuzz the Thrift protocol parsers. This is **not** integrated with oss-fuzz, so all fuzzing must be run locally. **Supported platform: Linux only.** The fuzzers are opt-in and are **not** built by `make check`; run `make build-fuzzers` (or `./buildfuzzers.sh`) explicitly.
We use [SharpFuzz](https://github.com/Metalnem/sharpfuzz) (and its libfuzzer variant) to fuzz the Thrift protocol parsers. This is **not** integrated with oss-fuzz, so all fuzzing must be run locally. **Supported platform: Linux only.**

`make check` compiles the 12 fuzzer variants without SharpFuzz IL
instrumentation, so changes that break the fuzzer build will fail CI.
Full, instrumented builds suitable for actually running a fuzzer remain
opt-in: run `make build-fuzzers` (or `./buildfuzzers.sh`), which
additionally requires the SharpFuzz.CommandLine global tool and the
`libfuzzer-dotnet` native driver as described below.

## Prerequisites

Expand Down
76 changes: 51 additions & 25 deletions lib/netstd/buildfuzzers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,59 @@

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

# 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
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 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
# 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
Expand Down Expand Up @@ -108,6 +129,11 @@ for protocol in Binary Compact Json; do
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
Expand Down Expand Up @@ -143,4 +169,4 @@ while IFS= read -r -d '' dll; do
fi
done < <(find "$OUTPUT_DIR" -maxdepth 1 -type f -name "*.dll" -print0)

echo "Build and instrumentation complete."
echo "Build and instrumentation complete."
Loading