diff --git a/CMakeLists.txt b/CMakeLists.txt index b29e315cc3ab30e98383bdf8adfadaa2c23f7a51..302dfcc686685c1a05efa9b732baebefe8af676f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,10 +29,12 @@ option(ENABLE_CCACHE "Whether to use ccache to speed up compiling" ON) option(ENABLE_ASAN "Whether to turn AddressSanitizer ON or OFF" OFF) option(ENABLE_TESTING "Whether to turn unit test ON or OFF" ON) option(ENABLE_UBSAN "Whether to turn Undefined Behavior Sanitizer ON or OFF" OFF) +option(ENABLE_FUZZ_TEST "Whether to turn Fuzz Test ON or OFF" OFF) message(STATUS "ENABLE_ASAN: ${ENABLE_ASAN}") message(STATUS "ENABLE_TESTING: ${ENABLE_TESTING}") message(STATUS "ENABLE_UBSAN: ${ENABLE_UBSAN}") +message(STATUS "ENABLE_FUZZ_TEST: ${ENABLE_FUZZ_TEST}") if (ENABLE_NATIVE) @@ -237,6 +239,13 @@ if(ENABLE_UBSAN) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined") endif() +if(ENABLE_FUZZ_TEST) + check_cxx_compiler_flag("-fsanitize=fuzzer" ENABLE_FUZZ_OK) + if (NOT ENABLE_FUZZ_OK) + MESSAGE(FATAL_ERROR "The compiler does not support fuzz testing") + endif() +endif() + macro(nebula_add_executable) cmake_parse_arguments( nebula_exec # prefix @@ -259,7 +268,7 @@ endmacro() macro(nebula_add_test) cmake_parse_arguments( nebula_test # prefix - "DISABLED" # <options> + "DISABLED;FUZZER" # <options> "NAME" # <one_value_args> "SOURCES;OBJECTS;LIBRARIES" # <multi_value_args> ${ARGN} @@ -272,7 +281,13 @@ macro(nebula_add_test) LIBRARIES ${nebula_test_LIBRARIES} ) - if (NOT ${nebula_test_DISABLED}) + if (${nebula_test_FUZZER}) + #Currently only Clang supports fuzz test + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set_target_properties(${nebula_test_NAME} PROPERTIES COMPILE_FLAGS "-g -fsanitize=fuzzer") + set_target_properties(${nebula_test_NAME} PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") + endif() + elseif (NOT ${nebula_test_DISABLED}) string(REGEX REPLACE "${CMAKE_SOURCE_DIR}/src/(.*)/test" "\\1" test_group ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME ${nebula_test_NAME} COMMAND ${nebula_test_NAME}) set_tests_properties(${nebula_test_NAME} PROPERTIES LABELS ${test_group}) diff --git a/src/parser/test/CMakeLists.txt b/src/parser/test/CMakeLists.txt index ef6d5b050a158eb795f75ce7fb81c7dd978cc961..b3e0f5b71f2d46d42072568b2795f3de85bab100 100644 --- a/src/parser/test/CMakeLists.txt +++ b/src/parser/test/CMakeLists.txt @@ -38,3 +38,7 @@ nebula_add_executable( OBJECTS ${PARSER_TEST_LIBS} LIBRARIES follybenchmark boost_regex ${THRIFT_LIBRARIES} wangle ) + +if(ENABLE_FUZZ_TEST) + nebula_add_subdirectory(fuzzing) +endif() diff --git a/src/parser/test/fuzzing/CMakeLists.txt b/src/parser/test/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a408d77ef29a9b19de174b5b68deb6e70f05bd67 --- /dev/null +++ b/src/parser/test/fuzzing/CMakeLists.txt @@ -0,0 +1,7 @@ +nebula_add_test( + NAME parser_fuzzer + FUZZER ON + SOURCES ParserFuzzer.cpp + OBJECTS ${PARSER_TEST_LIBS} + LIBRARIES ${THRIFT_LIBRARIES} wangle +) diff --git a/src/parser/test/fuzzing/ParserFuzzer.cpp b/src/parser/test/fuzzing/ParserFuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b98b949f06ed75c4ddaaef7494d9192c730fd7a --- /dev/null +++ b/src/parser/test/fuzzing/ParserFuzzer.cpp @@ -0,0 +1,16 @@ +/* Copyright (c) 2019 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "base/Base.h" +#include "parser/GQLParser.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + nebula::GQLParser parser; + const char* ptr = reinterpret_cast<const char*>(data); + std::string query = {ptr, size}; + auto result = parser.parse(query); + return 0; +} diff --git a/src/parser/test/fuzzing/README.md b/src/parser/test/fuzzing/README.md new file mode 100644 index 0000000000000000000000000000000000000000..eeeb56952fdcac11068918c7510faaf769293b0a --- /dev/null +++ b/src/parser/test/fuzzing/README.md @@ -0,0 +1,11 @@ +# Nebula Graph Database fuzz testing + +Nebula-graph uses [libfuzzer](http://llvm.org/docs/LibFuzzer.html) for fuzz test. +If you want to use fuzz test, then you need to use the [Clang](https://clang.llvm.org/) to compile Nebula. +In order to better show the test results, it is recommended to enable the addresssanitizer(-DENABLE_ASAN=ON) option when compiling. + +# Running fuzz tests locally + +``` shell + ./parser_fuzzer -dict=nebula.dict +``` diff --git a/src/parser/test/fuzzing/nebula.dict b/src/parser/test/fuzzing/nebula.dict new file mode 100644 index 0000000000000000000000000000000000000000..70a054b26e4d66015b935ed76a03189c47639205 --- /dev/null +++ b/src/parser/test/fuzzing/nebula.dict @@ -0,0 +1,180 @@ +# AFL dictionary for NGQL +# usage: ./parser_fuzzer -dict=nebula.dict +# +# Copyright (c) 2019 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License, +# attached with Common Clause Condition 1.0, found in the LICENSES directory. + + +function_abs=" abbs(1)" +function_floor=" floor(1.1)" +function_ceil=" ceil(1.1)" +function_round=" round(1, 1)" +function_sqrt=" sqrt(1)" +function_cbrt=" cbrt(1)" +function_hypot=" hypot(1, 1)" +function_pow=" pow(1, 1)" +function_exp=" exp(1)" +function_exp2=" exp(1)" +function_log=" log(1)" +function_log2=" log2(1)" +function_log10=" log10(1)" +function_sin=" sin(1)" +function_asin=" asin(1)" +function_cos=" cos(1)" +function_acos=" acos(1)" +function_tan=" tan(1)" +function_atan=" atan(1)" +function_rand32=" rand32(1, 1)" +function_rand64=" rand64(1, 1)" +function_now=" now()" +function_strcasecmp=" strcasecmp(1, 1)" +function_lower=" lower(1)" +function_upper=" upper(1)" +function_length=" length(1)" +function_trim=" trim(1)" +function_ltrim=" ltrim(1)" +function_rtrim=" rtrim(1)" +function_left=" left(1, 1)" +function_right=" right(1, 1)" +function_substr=" substr(1,1,1)" +function_hash=" hash(1)" +function_now=" now()" + +keyword_GO="GO" +keyword_AS="AS" +keyword_TO="TO" +keyword_OR="OR" +keyword_AND="AND" +keyword_XOR="XOR" +keyword_USE="USE" +keyword_SET="SET" +keyword_FROM="FROM" +keyword_WHERE="WHERE" +keyword_MATCH="MATCH" +keyword_INSERT="INSERT" +keyword_VALUES="VALUES" +keyword_YIELD="YIELD" +keyword_RETURN="RETURN" +keyword_CREATE="CREATE" +keyword_DESCRIBE="DESCRIBE" +keyword_DESC="DESC" +keyword_VERTEX="VERTEX" +keyword_EDGE="EDGE" +keyword_EDGES="EDGES" +keyword_UPDATE="UPDATE" +keyword_UPSERT="UPSET" +keyword_WHEN="WHEN" +keyword_DELETE="DELETE" +keyword_FIND="FIND" +keyword_ALTER="ALTER" +keyword_STEPS="STEPS" +keyword_OVER="OVER" +keyword_UPTO="UPTO" +keyword_REVERSELY="REVERSELY" +keyword_SPACE="SPACE" +keyword_SPACES="SPACES" +keyword_INT="INT" +keyword_BIGINT="BIGINT" +keyword_DOUBLE="DOUBLE" +keyword_STRING="STRING" +keyword_BOOL="BOOL" +keyword_TAG="TAG" +keyword_TAGS="TAGS" +keyword_UNION="UNION" +keyword_INTERSECT="INTERSECT" +keyword_MINUS="MINUS" +keyword_NO="NO" +keyword_OVERWRITE="OVERWRITE" +keyword_TRUE="TRUE" +keyword_FALSE="FALSE" +keyword_SHOW="SHOW" +keyword_ADD="ADD" +keyword_HOSTS="HOSTS" +keyword_TIMESTAMP="TIMESTAMP" +keyword_PARTITION="PARTITION" +keyword_REPLICA_F="REPLICA_F" +keyword_DROP="DROP" +keyword_REMOVE="REMOVE" +keyword_IF="IF" +keyword_NOT="NOT" +keyword_EXISTS="EXISTS" +keyword_WITH="WITH" +keyword_FIRSTNAME="FIRSTNAME" +keyword_LASTNAME="LASTNAME" +keyword_EMAIL="EMAIL" +keyword_PHONE="PHONE" +keyword_USER="USER" +keyword_USERS="USERS" +keyword_PASSWORD="PASSWORD" +keyword_CHANGE="CHANGE" +keyword_ROLE="ROLE" +keyword_GOD="GOD" +keyword_ADMIN="ADMIN" +keyword_GUEST="GUEST" +keyword_GRANT="GRANT" +keyword_REVOKE="REVOKE" +keyword_ON="ON" +keyword_ROLES="ROLES" +keyword_BY="BY" +keyword_IN="IN" +keyword_TTL_DURAT="TTL_DURAT" +keyword_TTL_COL="TTL_COL" +keyword_DOWNLOAD="DOWNLOAD" +keyword_HDFS="HDFS" +keyword_ORDER="ORDER" +keyword_INGEST="INGEST" +keyword_ASC="ASC" +keyword_DISTINCT="DISTINCT" +keyword_VARIABLES="VARIABLES" +keyword_GET="GET" +keyword_GRAPH="GRAPH" +keyword_META="META" +keyword_STORAGE="STORAGE" +keyword_FETCH="FETCH" +keyword_PROP="PROP" +keyword_ALL="ALL" +keyword_BALANCE="BALANCE" +keyword_LEADER="LEADER" +keyword_OF="OF" + +operator_PLUS=" +" +operator_MINUS=" -" +operator_MUL=" *" +operator_DIV=" /" +operator_MOD=" %" +operator_NOT=" !" +operator_XOR=" ^" +operator_LT=" < " +operator_LE=" <= " +operator_GT=" > " +operator_GE=" >= " +operator_EQ=" == " +operator_NE=" != " +operator_AND=" && " +operator_OR=" || " +operator_LARROW="<-" +operator_RARROW="->" +operator_COMMA="." +operator_PIPE=" | " +operator_PIPE_START=" $$." +operator_PIPE_END=" $^." +operator_INPUT_REF=" $-." +operator_AT=" @" + +RESERVE_PROPID="._id " +RESERVE_PROPSRC="._src " +RESERVE_PROPDST="._dst " +RESERVE_PROPRANK="._rank " + +snippet_comment=" /* */" +snippet_semicolon=" ;" +snippet_over_star=" over * " +snippet_timestamp=" 1551331900" +snippet_ref=" a.b" +snippet_go=" go from 1 over dummy " +snippet_where=" go from 1 over dummy where " +snippet_yield=" go from 1 over dummy,like where like._id > 10 yield " +snippet_yield2=" go from 1 over dummy,like where like._id > 10 yield like.a " +