Auto merge of #4547 - zebambam:add_libfuzzer_support, r=str4d
Add libfuzzer support - Added libfuzzer support to the build system in zcutil. - Added UniValue::Read fuzzer, dict, corpus. I made a slight change to the build.sh script so as to separate dependency building vs src building, just so that I can layer the docker containers for building over in another repo to speed up the continuous build processes that will want to build multiple fuzzers from the same commit. Closes #4548
This commit is contained in:
commit
9e117fdebe
|
@ -2,11 +2,43 @@
|
|||
#include "chainparams.h"
|
||||
#include "proof_verifier.h"
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
extern bool CheckBlock(
|
||||
const CBlock& block,
|
||||
CValidationState& state,
|
||||
const CChainParams& chainparams,
|
||||
libzcash::ProofVerifier& verifier,
|
||||
bool fCheckPOW = true,
|
||||
bool fCheckMerkleRoot = true);
|
||||
|
||||
bool init_done = false;
|
||||
|
||||
const CChainParams& chainparams = NULL;
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
|
||||
|
||||
int fuzz_CheckBlock(CBlock block) {
|
||||
int retval = 0;
|
||||
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
if (!init_done) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
chainparams = Params()
|
||||
init_done = true;
|
||||
}
|
||||
|
||||
CValidationState state;
|
||||
|
||||
// We don't check the PoW or Merkle tree root in order to reach more code.
|
||||
|
||||
if (!CheckBlock(block, state, chainparams, verifier, false, false)) {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef FUZZ_WITH_AFL
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
CBlock block;
|
||||
CAutoFile filein(fopen(argv[1], "rb"), SER_DISK, CLIENT_VERSION);
|
||||
try {
|
||||
|
@ -14,17 +46,22 @@ int main (int argc, char *argv[]) {
|
|||
} catch (const std::exception& e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We don't load the SNARK parameters because it's too slow. This means that
|
||||
// valid blocks with shielded transactions will generate a crash.
|
||||
|
||||
const CChainParams& chainparams = Params();
|
||||
auto verifier = ProofVerifier::Disabled();
|
||||
CValidationState state;
|
||||
// We don't check the PoW or Merkle tree root in order to reach more code.
|
||||
if (!CheckBlock(block, state, chainparams, verifier, false, false)) {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return fuzz_CheckBlock(block);
|
||||
}
|
||||
|
||||
#endif // FUZZ_WITH_AFL
|
||||
#ifdef FUZZ_WITH_LIBFUZZER
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
CBlock block;
|
||||
CDataStream ds((const char *)Data, (const char *)Data+Size, SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ds >> block;
|
||||
} catch (const std::exception &e) {
|
||||
return -1;
|
||||
}
|
||||
fuzz_CheckBlock(block);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
#include <bits/stdc++.h>
|
||||
#include <string>
|
||||
|
||||
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
|
||||
|
||||
// actual fuzzer
|
||||
|
||||
bool fuzz_DecodeHexTxFunction (const std::string& strHexTx) {
|
||||
CTransaction tx;
|
||||
return DecodeHexTx(tx, strHexTx);
|
||||
}
|
||||
|
||||
#ifdef FUZZ_WITH_AFL
|
||||
|
||||
// AFL
|
||||
|
||||
int fuzz_DecodeHexTx (int argc, char *argv[]) {
|
||||
std::ifstream t(argv[1]);
|
||||
|
@ -15,3 +23,17 @@ int fuzz_DecodeHexTx (int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
int main (int argc, char *argv[]) { return fuzz_DecodeHexTx(argc, argv); }
|
||||
|
||||
#endif
|
||||
#ifdef FUZZ_WITH_LIBFUZZER
|
||||
|
||||
// libfuzzer
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
std::string s;
|
||||
s.assign((const char *)Data, Size);
|
||||
fuzz_DecodeHexTxFunction (s);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "addrman.h"
|
||||
#include "streams.h"
|
||||
|
||||
|
||||
#ifdef FUZZ_WITH_AFL
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
CAddrMan addrman;
|
||||
CAutoFile filein(fopen(argv[1], "rb"), SER_DISK, CLIENT_VERSION);
|
||||
|
@ -11,3 +14,20 @@ int main (int argc, char *argv[]) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FUZZ_WITH_LIBFUZZER
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
CAddrMan addrman;
|
||||
CDataStream ds(Data, Data+Size, SER_DISK, CLIENT_VERSION);
|
||||
try {
|
||||
ds >> addrman;
|
||||
} catch (const std::exception &e) {
|
||||
return 0;
|
||||
}
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#include <bits/stdc++.h>
|
||||
|
||||
// actual fuzzer
|
||||
|
||||
bool fuzz_TxDeserializeFunction (const std::vector<unsigned char> txData) {
|
||||
CTransaction tx;
|
||||
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -9,6 +13,9 @@ bool fuzz_TxDeserializeFunction (const std::vector<unsigned char> txData) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef FUZZ_WITH_AFL
|
||||
|
||||
// AFL
|
||||
|
||||
int fuzz_TxDeserialize (int argc, char *argv[]) {
|
||||
std::ifstream t(argv[1]);
|
||||
|
@ -19,3 +26,18 @@ int fuzz_TxDeserialize (int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
int main (int argc, char *argv[]) { return fuzz_TxDeserialize(argc, argv); }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FUZZ_WITH_LIBFUZZER
|
||||
|
||||
// libFuzzer
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
std::vector<unsigned char> vect(Size);
|
||||
memcpy(vect.data(), Data, Size);
|
||||
fuzz_TxDeserializeFunction(vect);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "txmempool.h"
|
||||
|
||||
#ifdef FUZZ_WITH_AFL
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
CFeeRate rate;
|
||||
CTxMemPool mempool(rate);
|
||||
|
@ -11,3 +13,22 @@ int main (int argc, char *argv[]) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FUZZ_WITH_LIBFUZZER
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
CFeeRate rate;
|
||||
CTxMemPool mempool(rate);
|
||||
CAutoFile est_filein(fmemopen(Data, Size, "rb"), SER_DISK, CLIENT_VERSION);
|
||||
|
||||
if (mempool.ReadFeeEstimates(est_filein)) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
kw1="{"
|
||||
kw2="}"
|
||||
kw5="["
|
||||
kw6="]"
|
||||
kw7=":"
|
||||
kw8=","
|
||||
kw9="\""
|
|
@ -0,0 +1,29 @@
|
|||
#include "univalue.h"
|
||||
|
||||
int fuzz_UniValue_Read(std::string notquitejson) {
|
||||
UniValue valRequest;
|
||||
if (!valRequest.read(notquitejson)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef FUZZ_WITH_AFL
|
||||
|
||||
#error "The AFL version of this fuzzer has not yet been implemented."
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
// not implemented
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // FUZZ_WITH_AFL
|
||||
#ifdef FUZZ_WITH_LIBFUZZER
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
std::string s;
|
||||
s.assign((const char *)Data, Size);
|
||||
return fuzz_UniValue_Read(s);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1 @@
|
|||
"This is a string that never ends, yes it goes on and on, my friends.
|
|
@ -0,0 +1 @@
|
|||
{"Extra value after close": true} "misplaced quoted value"
|
|
@ -0,0 +1 @@
|
|||
{"Illegal expression": 1 + 2}
|
|
@ -0,0 +1 @@
|
|||
{"Illegal invocation": alert()}
|
|
@ -0,0 +1 @@
|
|||
{"Numbers cannot have leading zeroes": 013}
|
|
@ -0,0 +1 @@
|
|||
{"Numbers cannot be hex": 0x14}
|
|
@ -0,0 +1 @@
|
|||
["Illegal backslash escape: \x15"]
|
|
@ -0,0 +1 @@
|
|||
[\naked]
|
|
@ -0,0 +1 @@
|
|||
["Illegal backslash escape: \017"]
|
|
@ -0,0 +1 @@
|
|||
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
|
@ -0,0 +1 @@
|
|||
{"Missing colon" null}
|
|
@ -0,0 +1 @@
|
|||
["Unclosed array"
|
|
@ -0,0 +1 @@
|
|||
{"Double colon":: null}
|
|
@ -0,0 +1 @@
|
|||
{"Comma instead of colon", null}
|
|
@ -0,0 +1 @@
|
|||
["Colon instead of comma": false]
|
|
@ -0,0 +1 @@
|
|||
["Bad value", truth]
|
|
@ -0,0 +1 @@
|
|||
['single quote']
|
|
@ -0,0 +1 @@
|
|||
[" tab character in string "]
|
|
@ -0,0 +1 @@
|
|||
["tab\ character\ in\ string\ "]
|
|
@ -0,0 +1,2 @@
|
|||
["line
|
||||
break"]
|
|
@ -0,0 +1,2 @@
|
|||
["line\
|
||||
break"]
|
|
@ -0,0 +1 @@
|
|||
[0e]
|
|
@ -0,0 +1 @@
|
|||
{unquoted_key: "keys must be quoted"}
|
|
@ -0,0 +1 @@
|
|||
[0e+]
|
|
@ -0,0 +1 @@
|
|||
[0e+-1]
|
|
@ -0,0 +1 @@
|
|||
{"Comma instead if closing brace": true,
|
|
@ -0,0 +1 @@
|
|||
["mismatch"}
|
|
@ -0,0 +1 @@
|
|||
{} garbage
|
|
@ -0,0 +1 @@
|
|||
[ true true true [] [] [] ]
|
|
@ -0,0 +1 @@
|
|||
{"a":}
|
|
@ -0,0 +1 @@
|
|||
{"a":1 "b":2}
|
|
@ -0,0 +1 @@
|
|||
["\ud834"]
|
|
@ -0,0 +1 @@
|
|||
["\udd61"]
|
|
@ -0,0 +1 @@
|
|||
["extra comma",]
|
|
@ -0,0 +1 @@
|
|||
["揣。"]
|
|
@ -0,0 +1 @@
|
|||
["<22><><EFBFBD>"]
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
["double extra comma",,]
|
|
@ -0,0 +1 @@
|
|||
[ , "<-- missing value"]
|
|
@ -0,0 +1 @@
|
|||
["Comma after the close"],
|
|
@ -0,0 +1 @@
|
|||
["Extra close"]]
|
|
@ -0,0 +1 @@
|
|||
{"Extra comma": true,}
|
|
@ -0,0 +1,58 @@
|
|||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
|
@ -0,0 +1 @@
|
|||
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"JSON Test Pattern pass3": {
|
||||
"The outermost value": "must be an object or array.",
|
||||
"In this test": "It is an object."
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f"]
|
|
@ -0,0 +1 @@
|
|||
["a§■𐎒𝅘𝅥𝅯"]
|
|
@ -0,0 +1 @@
|
|||
"abcdefghijklmnopqrstuvwxyz"
|
|
@ -0,0 +1 @@
|
|||
7
|
|
@ -0,0 +1 @@
|
|||
true
|
|
@ -0,0 +1 @@
|
|||
false
|
|
@ -0,0 +1 @@
|
|||
null
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
set -exu -o pipefail
|
||||
|
||||
for d in src/fuzzing/*/ ; do
|
||||
fuzz_cases+="$(basename "$d"), "
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
set -ex -o pipefail
|
||||
|
||||
export ARGS=$@
|
||||
|
||||
instrument=(
|
||||
"\/src$"
|
||||
|
@ -22,10 +21,22 @@ fi
|
|||
|
||||
case $0 in
|
||||
*zcash-wrapper-g++)
|
||||
COMPILER="g++"
|
||||
OCOMPILER="g++"
|
||||
ACOMPILER=$OCOMPILER
|
||||
;;
|
||||
*zcash-wrapper-gcc)
|
||||
COMPILER="gcc"
|
||||
OCOMPILER="gcc"
|
||||
ACOMPILER=$OCOMPILER
|
||||
;;
|
||||
*zcash-wrapper-clang)
|
||||
OCOMPILER="clang-6.0"
|
||||
ACOMPILER="clang-fast"
|
||||
CFLAGS="-fsanitize=address -static"
|
||||
;;
|
||||
*zcash-wrapper-clang++)
|
||||
OCOMPILER="clang++-6.0"
|
||||
ACOMPILER="clang-fast++"
|
||||
CPPFLAGS="-fsanitize=address -static"
|
||||
;;
|
||||
*zcash-wrapper)
|
||||
echo "Call this script instead of your regular compiler, and if the absolute path of the CWD the wrapper was called from matches a regex in the array 'instrument', it will call AFL to instrument the resulting binary. Otherwise it will call either g++ or gcc depending on how it was invoked. \$AFL_INSTALL_DIR must be set to the path where AFL is installed."
|
||||
|
@ -40,9 +51,9 @@ do
|
|||
if echo -- "`pwd`" | grep "$i"; then
|
||||
# We found a match, let's instrument this one.
|
||||
echo "Matched directory `pwd` to instrument element $i. Instrumenting this call." >> "$AFL_LOG_DIR/zcash-build-wrapper.log"
|
||||
exec -- "$AFL_INSTALL_DIR/afl-$COMPILER" "$@"
|
||||
exec -- "$AFL_INSTALL_DIR/afl-$ACOMPILER" "$@"
|
||||
fi
|
||||
done
|
||||
|
||||
# No match, just pass-through.
|
||||
exec -- "$COMPILER" "$@"
|
||||
exec -- "$OCOMPILER" "$@"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
zcash-wrapper
|
|
@ -0,0 +1 @@
|
|||
zcash-wrapper
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
set +x
|
||||
|
||||
function cmd_pref() {
|
||||
if type -p "$2" > /dev/null; then
|
||||
|
@ -69,6 +70,12 @@ as --version
|
|||
ld -v
|
||||
|
||||
HOST="$HOST" BUILD="$BUILD" "$MAKE" "$@" -C ./depends/
|
||||
|
||||
if [ "${BUILD_STAGE:-all}" = "depends" ]
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
./autogen.sh
|
||||
CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure $CONFIGURE_FLAGS
|
||||
"$MAKE" "$@"
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
usage() {
|
||||
echo ""
|
||||
echo "$0 <build stage> <options> <passthrough build arguments>"
|
||||
echo ""
|
||||
echo "Build a fuzzer in the local repo using the following options:"
|
||||
echo ""
|
||||
echo "<build stage>:"
|
||||
echo " either \"depends\" or \"fuzzer\""
|
||||
echo ""
|
||||
echo "<options>:"
|
||||
echo " -f,--fuzzer <fuzzername> (ignored if building \"depends\")"
|
||||
echo " [-s,--sanitizers <sanitizers>]"
|
||||
echo " [-i,--instrument <instrument>]"
|
||||
echo " [-l,--logfile <logfile>] # default is ./zcash-build-wrapper.log"
|
||||
echo " [-h,--help]"
|
||||
echo ""
|
||||
echo "Where fuzzer is an entry in ./src/fuzzing/*, the default sanitizer"
|
||||
echo "is \"address\" and default instrument is ( \"^.*/src/$\" )."
|
||||
echo ""
|
||||
exit -1
|
||||
}
|
||||
|
||||
die() {
|
||||
echo $1
|
||||
exit -1
|
||||
}
|
||||
|
||||
# parse command line options
|
||||
|
||||
POSITIONAL=()
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
|
||||
case $key in
|
||||
-f|--fuzzer)
|
||||
FUZZER_NAME="$2"
|
||||
if [ ! -f "./src/fuzzing/$FUZZER_NAME/fuzz.cpp" ]
|
||||
then
|
||||
die "Cannot find source code for fuzzer."
|
||||
fi
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-s|--sanitizers)
|
||||
LLVM_SANITIZERS="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-i|--instrument)
|
||||
INSTRUMENT_CODE="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-l|--logfile)
|
||||
LOGFILE="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
POSITIONAL+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# positional arguments
|
||||
|
||||
if [ ${#POSITIONAL[@]} -lt 1 ]
|
||||
then
|
||||
usage
|
||||
else
|
||||
BUILD_STAGE=${POSITIONAL[0]}
|
||||
fi
|
||||
|
||||
case "${BUILD_STAGE:-undefined}" in
|
||||
depends)
|
||||
FUZZER_NAME=notused
|
||||
# fine
|
||||
;;
|
||||
fuzzer)
|
||||
# fine
|
||||
;;
|
||||
*)
|
||||
# not fine
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
# required arguments
|
||||
|
||||
if [ "${FUZZER_NAME:-undefined}" = "undefined" ]
|
||||
then
|
||||
usage
|
||||
fi
|
||||
|
||||
# default values
|
||||
|
||||
if [ "${LLVM_SANITIZERS:-undefined}" = "undefined" ]
|
||||
then
|
||||
export LLVM_SANITIZERS="address"
|
||||
fi
|
||||
if [ "${INSTRUMENT_CODE:-undefined}" = "undefined" ]
|
||||
then
|
||||
export INSTRUMENT_CODE=("^.*\/src")
|
||||
fi
|
||||
if [ "${LOGFILE:-undefined}" = "undefined" ]
|
||||
then
|
||||
export LOGFILE=./zcash-build-wrapper.log
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
export ZCUTIL=$(realpath "./zcutil")
|
||||
|
||||
# overwrite the Linux make profile to use clang instead of GCC:
|
||||
|
||||
cat $ZCUTIL/../depends/hosts/linux.mk | sed -e 's/=gcc/=clang/g' | sed -e 's/=g++/=clang++/g' > x
|
||||
mv x $ZCUTIL/../depends/hosts/linux.mk
|
||||
|
||||
# the build_stage distinction helps to layer an intermediate docker
|
||||
# container for the built dependencies, so we can resume building
|
||||
# from there assuming no other build arguments have changed
|
||||
|
||||
if [ "$BUILD_STAGE" = "depends" ]
|
||||
then
|
||||
# make an empty fuzz file just so we can build dependencies
|
||||
> src/fuzz.cpp
|
||||
else
|
||||
cp "./src/fuzzing/$FUZZER_NAME/fuzz.cpp" src/fuzz.cpp || die "Can't copy fuzz.cpp for that fuzzer"
|
||||
fi
|
||||
|
||||
# sneak the variable into zcashd's build.sh
|
||||
|
||||
export BUILD_STAGE
|
||||
|
||||
# run build.sh with our compiler wrapper, and BUILD_STAGE environment set:
|
||||
|
||||
CONFIGURE_FLAGS="--enable-tests=no --disable-bench" \
|
||||
"$ZCUTIL/build.sh" \
|
||||
-j$(nproc) \
|
||||
"CC=$ZCUTIL/libfuzzer/zcash-wrapper-clang" \
|
||||
"CXX=$ZCUTIL/libfuzzer/zcash-wrapper-clang++" "${POSITIONAL[@]:1}" || die "Build failed at stage $BUILD_STAGE."
|
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# you shouldn't normally be calling this script directly, it should be called
|
||||
# by build.sh, but only when build.sh is invoked from libfuzzer-build.sh.
|
||||
|
||||
set -ex -o pipefail
|
||||
|
||||
# logging functions
|
||||
|
||||
export green="\e[92m"
|
||||
export red="\e[95m"
|
||||
export normal="\e[0m"
|
||||
|
||||
export color=$normal
|
||||
|
||||
function log {
|
||||
while read line
|
||||
do
|
||||
(echo ; echo -e "${color}${line}${normal}") >> "$LOGFILE" ;
|
||||
done
|
||||
}
|
||||
|
||||
# command-line parsing
|
||||
|
||||
export FINAL_LINK=0 # by default we using -fsanitize=fuzzer-no-link
|
||||
|
||||
for arg do
|
||||
shift
|
||||
if [ "$arg" = "-fPIE" ] # no more pie
|
||||
then
|
||||
set -- "$@" "-fPIC" "-fno-pie"
|
||||
continue
|
||||
fi
|
||||
if [ "$arg" = "-pie" ]
|
||||
then
|
||||
set -- "$@" "-no-pie"
|
||||
continue
|
||||
fi
|
||||
if [ "$arg" = "-o" ] # here an output file is being specified
|
||||
then
|
||||
if [ "$1" = "zcashd" ] # here zcashd is the output file
|
||||
then
|
||||
export FINAL_LINK=1 # we should use -fsanitize=fuzzer because that links libfuzzer
|
||||
fi
|
||||
# note no continue, we fall through to default set
|
||||
fi
|
||||
set -- "$@" "$arg"
|
||||
done
|
||||
|
||||
# which source dirs to instrument
|
||||
|
||||
if [ "$dirs_to_instrument" = "" ]
|
||||
then
|
||||
export dirs_to_instrument=("^.*\/src$")
|
||||
fi
|
||||
|
||||
# Store the command line we were given to a file
|
||||
|
||||
echo "`hostname`:`pwd` \$" | log
|
||||
echo -- "original command: $0 $@" | log
|
||||
|
||||
# decide on a sanitizer option beyond just fuzzing:
|
||||
# to link nor not to link libfuzzer we only link on
|
||||
# the final call, to the linker.
|
||||
|
||||
if [ "$LLVM_SANITIZE" = "" ]
|
||||
then
|
||||
export LLVM_SANITIZE="address" # you can override this behavior by setting this environment variable first
|
||||
fi
|
||||
|
||||
if [ "$FINAL_LINK" = "1" ]
|
||||
then
|
||||
export LLVM_SANITIZE="-fsanitize=fuzzer,$LLVM_SANITIZE"
|
||||
else
|
||||
export LLVM_SANITIZE="-fsanitize=fuzzer-no-link,$LLVM_SANITIZE"
|
||||
fi
|
||||
|
||||
|
||||
# Work out which compiler we were called as
|
||||
|
||||
case $0 in
|
||||
*zcash-wrapper-clang)
|
||||
COMPILER="clang"
|
||||
export DEFINES_FLAGS="${CFLAGS} -DZCASH_FUZZ=1 -DFUZZ_WITH_LIBFUZZER=1 -fPIC"
|
||||
export INSTRUMENT_FLAGS="${DEFINES_FLAGS} ${LLVM_SANITIZE}"
|
||||
;;
|
||||
*zcash-wrapper-clang++)
|
||||
COMPILER="clang++"
|
||||
export DEFINES_FLAGS="${CXXFLAGS} -DZCASH_FUZZ=1 -DFUZZ_WITH_LIBFUZZER=1 -fPIC"
|
||||
export INSTRUMENT_FLAGS="${DEFINES_FLAGS} ${LLVM_SANITIZE}"
|
||||
;;
|
||||
*zcash-wrapper)
|
||||
echo -n "Call this script instead of your regular compiler, and if the absolute "
|
||||
echo -n "path of the CWD the wrapper was called from matches a regex in the "
|
||||
echo -n "array 'dirs_to_instrument', it will instrument the resulting object. "
|
||||
echo -n "Otherwise it will exec directly to the original compiler without "
|
||||
echo "changing arguments."
|
||||
echo -n "You can also set LLVM_SANITIZE to whatever sanitizers you'd like to use."
|
||||
echo -n "the default is 'address'. You don't need the -fsanitize=fuzzer part, "
|
||||
echo "this script handles that"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check if we should instrument
|
||||
|
||||
for i in "${dirs_to_instrument[@]}"
|
||||
do
|
||||
if echo -- "`pwd`" | grep "$i"; then
|
||||
# We found a match, let's instrument this one.
|
||||
echo "pwd (`pwd`) matches dirs_to_instrument array element ($i). Adding instrumentation flags..." | log
|
||||
echo "command with defines and instrumentation added:" | color=$green log
|
||||
echo -- "$COMPILER" $INSTRUMENT_FLAGS "$@" | log
|
||||
exec -- "$COMPILER" $INSTRUMENT_FLAGS "$@"
|
||||
fi
|
||||
done
|
||||
|
||||
# No match, just pass-through.
|
||||
|
||||
echo -e -- "${red}command with defines added:${normal}" | color=$red log
|
||||
echo -- "$COMPILER" $DEFINES_FLAGS "$@" | log
|
||||
exec -- "$COMPILER" $DEFINES_FLAGS "$@"
|
||||
|
|
@ -0,0 +1 @@
|
|||
zcash-wrapper
|
|
@ -0,0 +1 @@
|
|||
zcash-wrapper
|
Loading…
Reference in New Issue