Merge remote-tracking branch 'upstream/libyang2' into libyang2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 199cdee..149a3e4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,6 +42,8 @@
     option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
     option(ENABLE_COVERAGE "Build code coverage report from tests" OFF)
 endif()
+
+option(ENABLE_FUZZ_TARGETS "Build target programs suitable for fuzzing with AFL" OFF)
 #option(ENABLE_CALLGRIND_TESTS "Build performance tests to be run with callgrind" OFF)
 
 #option(ENABLE_CACHE "Enable data caching for schemas and hash tables for data (time-efficient at the cost of increased space-complexity)" ON)
@@ -408,6 +410,10 @@
     endif(CMOCKA_FOUND)
 endif(ENABLE_BUILD_TESTS)
 
+if(ENABLE_FUZZ_TARGETS)
+	add_subdirectory(tests/fuzz)
+endif(ENABLE_FUZZ_TARGETS)
+
 #if(GEN_LANGUAGE_BINDINGS AND GEN_CPP_BINDINGS)
 #    add_subdirectory(swig)
 #endif()
diff --git a/README.md b/README.md
index a185d0b..f5c641b 100644
--- a/README.md
+++ b/README.md
@@ -252,5 +252,9 @@
 * JavaScript
  * cmake option: `JAVASCRIPT_BINDING`
  * [README](./swig/javascript/README.md)
+ 
+## Fuzzing
 
+A YANG fuzzing target and fuzzing instructions are available in the `tests/fuzz` directory.
 
+An asciinema example describing the process of fuzzing libyang2 with the yangfuzz fuzz harness is available at https://asciinema.org/a/260417.
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
new file mode 100644
index 0000000..8ed9c90
--- /dev/null
+++ b/tests/fuzz/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+set(fuzz_targets yangfuzz)
+
+foreach(target_name IN LISTS fuzz_targets)
+    add_executable(${target_name} ${target_name}.c)
+    target_link_libraries(${target_name} yang)
+endforeach(target_name)
diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md
new file mode 100644
index 0000000..e07193f
--- /dev/null
+++ b/tests/fuzz/README.md
@@ -0,0 +1,40 @@
+# FUZZING
+yangfuzz, a simple YANG fuzz harness is available in this directory and
+is designed to be used with the [AFL](http://lcamtuf.coredump.cx/afl/) fuzzer.
+
+To build the fuzz target, the ENABLE_FUZZ_TARGETS option has to be enabled.
+
+To add AFL instrumentation when compiling libyang, the AFL clang-fast compiler
+should be used with the following cmake option:
+
+It is reccomended to set the build type to Release, since otherwise the fuzzer will detect failed asserts as crashes.
+
+```
+$ cmake -DENABLE_FUZZ_TARGETS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=path_to_afl/afl-clang-fast ..
+```
+
+After that the programs can be built by running make:
+```
+$ make
+```
+
+The yangfuzz executable will then be available in the root of the build directory that was used.
+
+The libyang yang test files available in the `tests/data/files` subdirectory can be used as initial
+test cases for fuzzing the programs with AFL.
+
+The files that will be used as starting test cases should be copied into a single directory. Those files should then be minimized by using afl-cmin and afl-tmin.
+Also, AFL will issue a warning about a decrease of performance when working with large files, so only smaller test cases should be used.
+
+To increase the speed of fuzzing, the test cases and AFL output files should be stored on a temporary RAM disk.
+If a new fuzz target is used, AFL persistent mode should be used. More about persistent mode can be read in the official AFL documentation.
+
+When all of the above is done the fuzzing process can begin. AFL supports running multiple instances of the fuzzer, which can speed up the
+process on multi core CPUs. The first fuzz instance should be started in master mode, and the other instances in slave mode.
+The total number of instances should usually be equal to the number of cores.
+
+Below is an example of running 2 instances. The -i flag specifies the testcase input directory, and the -o file specifies the directory the fuzzer will use for output.
+```
+afl-fuzz -i minimised_testcases/ -o syncdir/ -M fuzzer1 -- libyang/build/fuzz/yangfuzz @@
+afl-fuzz -i minimised_testcases/ -o syncdir/ -S fuzzer2 -- libyang/build/fuzz/yangfuzz @@
+```
diff --git a/tests/fuzz/yangfuzz.c b/tests/fuzz/yangfuzz.c
new file mode 100644
index 0000000..06d6076
--- /dev/null
+++ b/tests/fuzz/yangfuzz.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libyang.h"
+
+int main(int argc, char **argv) {
+	if (argc != 2) {
+		fprintf(stderr, "invalid usage\n");
+		exit(EXIT_FAILURE);
+	}
+
+
+	struct ly_ctx *ctx = NULL;
+	LY_ERR err;
+	while (__AFL_LOOP(100)) {
+		err = ly_ctx_new(NULL, 0, &ctx);
+		if (err != LY_SUCCESS) {
+			fprintf(stderr, "Failed to create context\n");
+			exit(EXIT_FAILURE);
+		}
+
+		lys_parse_path(ctx, argv[1], LYS_IN_YANG);
+		ly_ctx_destroy(ctx, NULL);
+	}
+
+	return 0;
+}