🔨 split AFL test in driver and test file

This commit is contained in:
Niels Lohmann 2016-12-22 11:09:26 +01:00
parent 048330b14b
commit a084e90f39
6 changed files with 91 additions and 63 deletions

2
.gitignore vendored
View file

@ -21,3 +21,5 @@ cmake-build-debug
test/test-*
.svn
test/thirdparty/Fuzzer/libFuzzer.a

View file

@ -49,14 +49,10 @@ doctest:
fuzz_testing:
rm -fr fuzz-testing
mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out
$(MAKE) fuzz CXX=afl-clang++
mv fuzz fuzz-testing
$(MAKE) parse_afl_fuzzer -C test CXX=afl-clang++
mv test/fuzzer parse_afl_fuzzer
find test/data/json_tests -size -5k -name *json | xargs -I{} cp "{}" fuzz-testing/testcases
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzz"
# the fuzzer binary
fuzz: test/src/fuzz.cpp src/json.hpp
$(CXX) -std=c++11 $(CXXFLAGS) $(FLAGS) $(CPPFLAGS) -I src $< $(LDFLAGS) -o $@
@echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer"
##########################################################################

View file

@ -78,3 +78,11 @@ TEST_PATTERN = "*"
TEST_PREFIX = ""
check: $(TESTCASES)
@cd .. ; for testcase in $(TESTCASES); do echo "Executing $$testcase..."; $(TEST_PREFIX)test/$$testcase $(TEST_PATTERN) || exit 1; done
##############################################################################
# fuzzer
##############################################################################
parse_afl_fuzzer:
$(CXX) $(CXXFLAGS) $(CPPFLAGS) src/fuzzer-driver_afl.cpp src/fuzzer-parse_json.cpp -o $@

View file

@ -1,34 +0,0 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 2.0.9
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Run "make fuzz_testing" and follow the instructions.
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*/
#include <json.hpp>
using json = nlohmann::json;
int main()
{
#ifdef __AFL_HAVE_MANUAL_CONTROL
while (__AFL_LOOP(1000))
{
#endif
try
{
json j(std::cin);
std::cout << j << std::endl;
}
catch (std::invalid_argument& e)
{
std::cout << "Invalid argument in parsing" << e.what() << '\n';
}
#ifdef __AFL_HAVE_MANUAL_CONTROL
}
#endif
}

View file

@ -0,0 +1,33 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 2.0.9
|_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on
an implementation of the `LLVMFuzzerTestOneInput` function which processes a
passed byte array.
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*/
#include <sstream>
#include <cstdint>
#include <iostream>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
int main()
{
#ifdef __AFL_HAVE_MANUAL_CONTROL
while (__AFL_LOOP(1000))
{
#endif
// copy stdin to stringstream to pass it to fuzzer as byte array
std::stringstream ss;
ss << std::cin.rdbuf();
LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
#ifdef __AFL_HAVE_MANUAL_CONTROL
}
#endif
}

View file

@ -1,16 +1,23 @@
// Copyright 2016 Google Inc.
//
// Licensed 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.
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 2.0.9
|_____|_____|_____|_|___| https://github.com/nlohmann/json
This file implements a parser test suitable for fuzz testing. Given a byte
array data, it performs the following steps:
- j1 = parse(data)
- s1 = serialize(j1)
- j2 = parse(s1)
- s2 = serialize(j2)
- assert(s1 == s2)
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
drivers.
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*/
#include <iostream>
#include <sstream>
@ -18,25 +25,41 @@
using json = nlohmann::json;
// see http://llvm.org/docs/LibFuzzer.html
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
try
{
std::stringstream s;
s << json::parse(data, data + size);
// step 1: parse input
json j1 = json::parse(data, data + size);
try
{
auto j = json::parse(s.str());
std::stringstream s2;
s2 << j;
assert(s.str() == s2.str());
assert(j == json::parse(s.str()));
// step 2: round trip
// first serialization
std::string s1 = j1.dump();
// parse serialization
json j2 = json::parse(s1);
// second serialization
std::string s2 = j2.dump();
// serializations must match
assert(s1 == s2);
}
catch (const std::invalid_argument&)
{
assert(0);
// parsing a JSON serialization must not fail
assert(false);
}
}
catch (const std::invalid_argument&) { }
catch (const std::invalid_argument&)
{
// parse errors are ok, because input may be random bytes
}
// return 0 - non-zero return values are reserved for future use
return 0;
}