This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/add-fuzzing in repository https://gitbox.apache.org/repos/asf/celix.git
commit 69ce5e1d39f9d8b7f564b9ff6dd6764d674633d6 Author: Pepijn Noltes <[email protected]> AuthorDate: Thu Aug 14 15:38:22 2025 +0200 Add fuzzing code Also improves benchmark setup --- libs/framework/benchmark/CMakeLists.txt | 9 +--- libs/utils/CMakeLists.txt | 19 +++++++++ libs/utils/benchmark/CMakeLists.txt | 9 +--- libs/utils/benchmark/src/StringHashmapBenchmark.cc | 2 +- libs/utils/fuzzing/CMakeLists.txt | 49 ++++++++++++++++++++++ libs/utils/fuzzing/filter_corpus/complex.txt | 1 + libs/utils/fuzzing/filter_corpus/simple.txt | 1 + libs/utils/fuzzing/properties_corpus/complex.json | 2 + libs/utils/fuzzing/properties_corpus/simple.json | 1 + libs/utils/fuzzing/src/FilterFuzz.cc | 23 ++++++++++ libs/utils/fuzzing/src/PropertiesFuzz.cc | 32 ++++++++++++++ libs/utils/fuzzing/src/VersionFuzz.cc | 23 ++++++++++ libs/utils/fuzzing/version_corpus/qualifier.txt | 1 + libs/utils/fuzzing/version_corpus/simple.txt | 1 + 14 files changed, 156 insertions(+), 17 deletions(-) diff --git a/libs/framework/benchmark/CMakeLists.txt b/libs/framework/benchmark/CMakeLists.txt index ba39fcbb4..875d2f7f3 100644 --- a/libs/framework/benchmark/CMakeLists.txt +++ b/libs/framework/benchmark/CMakeLists.txt @@ -15,14 +15,7 @@ # specific language governing permissions and limitations # under the License. -set(FRAMEWORK_BENCHMARK_DEFAULT "OFF") -find_package(benchmark QUIET) -if (benchmark_FOUND) - set(FRAMEWORK_BENCHMARK_DEFAULT "ON") -endif () - -celix_subproject(FRAMEWORK_BENCHMARK "Option to enable Celix framework benchmark" ${FRAMEWORK_BENCHMARK_DEFAULT}) -if (FRAMEWORK_BENCHMARK AND CELIX_CXX17) +if (ENABLE_BENCHMARKING AND CELIX_CXX17) set(CMAKE_CXX_STANDARD 17) find_package(benchmark REQUIRED) diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index 4b8c08a35..cb29f8f60 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -126,5 +126,24 @@ if (UTILS) add_subdirectory(gtest) endif () + + if (ENABLE_FUZZING) + add_library(utils_cuf STATIC ${UTILS_SRC}) + target_compile_definitions(utils_cuf PRIVATE CELIX_UTILS_STATIC_DEFINE) + target_include_directories(utils_cuf PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/include + ${CMAKE_CURRENT_LIST_DIR}/include_internal + ${CMAKE_BINARY_DIR}/celix/gen/includes/utils + ${CMAKE_BINARY_DIR}/celix/gen/src/utils + include_deprecated + ) + target_link_libraries(utils_cuf PUBLIC ${UTILS_PUBLIC_DEPS} ${UTILS_PRIVATE_DEPS}) + target_compile_options(utils_cuf PRIVATE -fsanitize=fuzzer-no-link,address) + target_link_options(utils_cuf PRIVATE -fsanitize=fuzzer-no-link,address) + target_link_options(utils_cuf PRIVATE -Wl,--gc-sections) + + add_subdirectory(fuzzing) + endif () + add_subdirectory(benchmark) endif () diff --git a/libs/utils/benchmark/CMakeLists.txt b/libs/utils/benchmark/CMakeLists.txt index 2f891e6cb..4c22fc2df 100644 --- a/libs/utils/benchmark/CMakeLists.txt +++ b/libs/utils/benchmark/CMakeLists.txt @@ -15,14 +15,7 @@ # specific language governing permissions and limitations # under the License. -set(UTILS_BENCHMARK_DEFAULT "OFF") -find_package(benchmark QUIET) -if (benchmark_FOUND) - set(UTILS_BENCHMARK_DEFAULT "ON") -endif () - -celix_subproject(UTILS_BENCHMARK "Option to enable Celix framework benchmark" ${UTILS_BENCHMARK_DEFAULT}) -if (UTILS_BENCHMARK) +if (ENABLE_BENCHMARKING) find_package(benchmark REQUIRED) add_executable(celix_string_hashmap_benchmark diff --git a/libs/utils/benchmark/src/StringHashmapBenchmark.cc b/libs/utils/benchmark/src/StringHashmapBenchmark.cc index 4552dd044..7ecfb81e0 100644 --- a/libs/utils/benchmark/src/StringHashmapBenchmark.cc +++ b/libs/utils/benchmark/src/StringHashmapBenchmark.cc @@ -100,7 +100,7 @@ public: return valDistribution(generator); } - const int MAX_LEN = 100; + static constexpr int MAX_LEN = 100; std::default_random_engine generator{}; std::uniform_int_distribution<int> lenDistribution{1,MAX_LEN}; std::uniform_int_distribution<int> charDistribution{'a','z'}; diff --git a/libs/utils/fuzzing/CMakeLists.txt b/libs/utils/fuzzing/CMakeLists.txt new file mode 100644 index 000000000..90b9eefaf --- /dev/null +++ b/libs/utils/fuzzing/CMakeLists.txt @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + + +add_executable(celix_properties_fuzzer src/PropertiesFuzz.cc) +target_link_libraries(celix_properties_fuzzer PRIVATE utils_cuf) +target_compile_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer,address) +target_link_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer,address) + +add_executable(celix_version_fuzzer src/VersionFuzz.cc) +target_link_libraries(celix_version_fuzzer PRIVATE utils_cuf) +target_compile_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer,address) +target_link_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer,address) + +add_executable(celix_filter_fuzzer src/FilterFuzz.cc) +target_link_libraries(celix_filter_fuzzer PRIVATE utils_cuf) +target_compile_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer,address) +target_link_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer,address) + +add_custom_command(TARGET celix_properties_fuzzer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/properties_corpus + $<TARGET_FILE_DIR:celix_properties_fuzzer>/properties_corpus +) + +add_custom_command(TARGET celix_version_fuzzer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/version_corpus + $<TARGET_FILE_DIR:celix_version_fuzzer>/version_corpus +) + +add_custom_command(TARGET celix_filter_fuzzer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/filter_corpus + $<TARGET_FILE_DIR:celix_filter_fuzzer>/filter_corpus +) + diff --git a/libs/utils/fuzzing/filter_corpus/complex.txt b/libs/utils/fuzzing/filter_corpus/complex.txt new file mode 100644 index 000000000..1ffe40511 --- /dev/null +++ b/libs/utils/fuzzing/filter_corpus/complex.txt @@ -0,0 +1 @@ +(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3))) diff --git a/libs/utils/fuzzing/filter_corpus/simple.txt b/libs/utils/fuzzing/filter_corpus/simple.txt new file mode 100644 index 000000000..bfa80ac8d --- /dev/null +++ b/libs/utils/fuzzing/filter_corpus/simple.txt @@ -0,0 +1 @@ +(key=value) diff --git a/libs/utils/fuzzing/properties_corpus/complex.json b/libs/utils/fuzzing/properties_corpus/complex.json new file mode 100644 index 000000000..070856559 --- /dev/null +++ b/libs/utils/fuzzing/properties_corpus/complex.json @@ -0,0 +1,2 @@ +{"key1":"value1","key2":"value2","object1":{"key3":"value3","key4":"value4"},"object2":{"key5":"value5"},"object3":{"object4":{"key6":"value6"}},"strArr":["value1","value2"],"intArr":[1,2],"realArr":[1.0,2.0],"boolArr":[true,false],"versionArr":["version<1.2.3.qualifier>","version<4.5.6.qualifier>"]} + diff --git a/libs/utils/fuzzing/properties_corpus/simple.json b/libs/utils/fuzzing/properties_corpus/simple.json new file mode 100644 index 000000000..29f05f6bf --- /dev/null +++ b/libs/utils/fuzzing/properties_corpus/simple.json @@ -0,0 +1 @@ +{"key":"value"} diff --git a/libs/utils/fuzzing/src/FilterFuzz.cc b/libs/utils/fuzzing/src/FilterFuzz.cc new file mode 100644 index 000000000..ddc5021c0 --- /dev/null +++ b/libs/utils/fuzzing/src/FilterFuzz.cc @@ -0,0 +1,23 @@ +#include <celix_filter.h> +#include <celix_err.h> +#include <cstdint> +#include <cstdlib> +#include <cstring> + +int filterParseFuzzOneInput(const uint8_t* data, size_t size) { + char* buffer = static_cast<char*>(malloc(size + 1)); + if (buffer == nullptr) { + return 0; + } + memcpy(buffer, data, size); + buffer[size] = '\0'; + + celix_filter_t* filter = celix_filter_create(buffer); + celix_filter_destroy(filter); + celix_err_resetErrors(); + + free(buffer); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return filterParseFuzzOneInput(data, size); } diff --git a/libs/utils/fuzzing/src/PropertiesFuzz.cc b/libs/utils/fuzzing/src/PropertiesFuzz.cc new file mode 100644 index 000000000..627c2dd56 --- /dev/null +++ b/libs/utils/fuzzing/src/PropertiesFuzz.cc @@ -0,0 +1,32 @@ +#include <celix_properties.h> +#include <celix_err.h> +#include <cstdint> +#include <cstdlib> +#include <cstring> + +int propertiesParserFuzzOneInput(const uint8_t* data, size_t size) { + int flags = 0; + if (size > 0) { + flags = data[0] & 0x3F; // use 6 bits for decode flags + data += 1; + size -= 1; + } + char* buffer = static_cast<char*>(malloc(size + 1)); + if (buffer == nullptr) { + return 0; + } + memcpy(buffer, data, size); + buffer[size] = '\0'; + + celix_properties_t* props = nullptr; + celix_properties_loadFromString(buffer, flags, &props); + celix_properties_destroy(props); + celix_err_resetErrors(); + + free(buffer); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return propertiesParserFuzzOneInput(data, size); +} diff --git a/libs/utils/fuzzing/src/VersionFuzz.cc b/libs/utils/fuzzing/src/VersionFuzz.cc new file mode 100644 index 000000000..b1fc7e67f --- /dev/null +++ b/libs/utils/fuzzing/src/VersionFuzz.cc @@ -0,0 +1,23 @@ +#include <celix_version.h> +#include <celix_err.h> +#include <cstdint> +#include <cstdlib> +#include <cstring> + +int versionParseFuzzOneInput(const uint8_t* data, size_t size) { + char* buffer = static_cast<char*>(malloc(size + 1)); + if (buffer == nullptr) { + return 0; + } + memcpy(buffer, data, size); + buffer[size] = '\0'; + + celix_version_t* version = celix_version_createVersionFromString(buffer); + celix_version_destroy(version); + celix_err_resetErrors(); + + free(buffer); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return versionParseFuzzOneInput(data, size); } diff --git a/libs/utils/fuzzing/version_corpus/qualifier.txt b/libs/utils/fuzzing/version_corpus/qualifier.txt new file mode 100644 index 000000000..da3ad8b4e --- /dev/null +++ b/libs/utils/fuzzing/version_corpus/qualifier.txt @@ -0,0 +1 @@ +2.0.0.qualifier diff --git a/libs/utils/fuzzing/version_corpus/simple.txt b/libs/utils/fuzzing/version_corpus/simple.txt new file mode 100644 index 000000000..0495c4a88 --- /dev/null +++ b/libs/utils/fuzzing/version_corpus/simple.txt @@ -0,0 +1 @@ +1.2.3
