From 888de357164fb43b19c5f53811c58f7634bc2dc7 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Thu, 14 Aug 2025 15:35:38 +0200 Subject: [PATCH 01/19] Add enable fuzzing build option Also align enable benchmark option with other enable option and improve package id --- CMakeLists.txt | 3 +++ conanfile.py | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d72ce4d76..cfb0c8c93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ endif () if(APPLE) set(CMAKE_MACOSX_RPATH 1) + set(CMAKE_CXX_FLAGS "-Wno-missing-template-arg-list-after-template-kw ${CMAKE_CXX_FLAGS}") endif() if(NOT APPLE) @@ -168,6 +169,8 @@ endif () option(ENABLE_CMAKE_WARNING_TESTS "Enable cmake warning tests to test warning prints" OFF) option(ENABLE_TESTING_ON_CI "Whether to enable testing on CI. This influence allowed timing errors during unit tests" OFF) option(ENABLE_DEPRECATED_WARNINGS "Enable compiler warnings for usage of deprecated functionality" OFF) +option(ENABLE_FUZZING "Enable fuzz testing, using LibFuzzer" OFF) #Note support for LibFuzzer is built-in for Clang +option(ENABLE_BENCHMARKING "Enable benchmarking, using Google Benchmark" OFF) if (NOT ENABLE_DEPRECATED_WARNINGS) set(CMAKE_C_FLAGS "-Wno-deprecated-declarations ${CMAKE_C_FLAGS}") diff --git a/conanfile.py b/conanfile.py index cfce0de63..577ee8c1c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -47,6 +47,8 @@ class CelixConan(ConanFile): "enable_address_sanitizer": False, "enable_undefined_sanitizer": False, "enable_thread_sanitizer": False, + "enable_fuzzing": False, + "enable_benchmarking": False, "install_find_modules": False, "build_all": False, "build_http_admin": False, @@ -145,6 +147,10 @@ def package_id(self): del self.info.options.enable_testing_on_ci del self.info.options.enable_ccache del self.info.options.enable_deprecated_warnings + del self.info.options.enable_testing + del self.info.options.enable_benchmarking + del self.info.options.enable_fuzzing + del self.info.options.enable_code_coverage def build_requirements(self): if self.options.enable_testing: @@ -308,6 +314,8 @@ def configure(self): self.options['openssl'].shared = True if self.options.enable_testing: self.options['gtest'].shared = True + if self.options.enable_benchmarking: + self.options['benchmark'].shared = True if (self.options.build_rsa_discovery_common or (self.options.build_rsa_remote_service_admin_dfi and self.options.enable_testing)): self.options['libxml2'].shared = True @@ -355,6 +363,8 @@ def requirements(self): self.requires("zlib/1.2.13", override=True) if self.options.build_event_admin_remote_provider_mqtt: self.requires("mosquitto/[>=2.0.3 <3.0.0]") + if self.options.enable_benchmarking: + self.requires("benchmark/[>=1.6.2]") self.validate() def generate(self): From 69ce5e1d39f9d8b7f564b9ff6dd6764d674633d6 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Thu, 14 Aug 2025 15:38:22 +0200 Subject: [PATCH 02/19] Add fuzzing code Also improves benchmark setup --- libs/framework/benchmark/CMakeLists.txt | 9 +--- libs/utils/CMakeLists.txt | 19 +++++++ libs/utils/benchmark/CMakeLists.txt | 9 +--- .../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 + .../fuzzing/properties_corpus/complex.json | 2 + .../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 +++++++++ .../fuzzing/version_corpus/qualifier.txt | 1 + libs/utils/fuzzing/version_corpus/simple.txt | 1 + 14 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 libs/utils/fuzzing/CMakeLists.txt create mode 100644 libs/utils/fuzzing/filter_corpus/complex.txt create mode 100644 libs/utils/fuzzing/filter_corpus/simple.txt create mode 100644 libs/utils/fuzzing/properties_corpus/complex.json create mode 100644 libs/utils/fuzzing/properties_corpus/simple.json create mode 100644 libs/utils/fuzzing/src/FilterFuzz.cc create mode 100644 libs/utils/fuzzing/src/PropertiesFuzz.cc create mode 100644 libs/utils/fuzzing/src/VersionFuzz.cc create mode 100644 libs/utils/fuzzing/version_corpus/qualifier.txt create mode 100644 libs/utils/fuzzing/version_corpus/simple.txt 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 @@ class StringHashmapBenchmark { return valDistribution(generator); } - const int MAX_LEN = 100; + static constexpr int MAX_LEN = 100; std::default_random_engine generator{}; std::uniform_int_distribution lenDistribution{1,MAX_LEN}; std::uniform_int_distribution 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 + $/properties_corpus +) + +add_custom_command(TARGET celix_version_fuzzer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/version_corpus + $/version_corpus +) + +add_custom_command(TARGET celix_filter_fuzzer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/filter_corpus + $/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 +#include +#include +#include +#include + +int filterParseFuzzOneInput(const uint8_t* data, size_t size) { + char* buffer = static_cast(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 +#include +#include +#include +#include + +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(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 +#include +#include +#include +#include + +int versionParseFuzzOneInput(const uint8_t* data, size_t size) { + char* buffer = static_cast(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 From 8ae7acd271f3f2bae72ebb0bef905246f3a96d9c Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Thu, 14 Aug 2025 15:42:00 +0200 Subject: [PATCH 03/19] Add fuzzing workflow and enable benchmarking options in CI configurations --- .github/workflows/fuzzing.yml | 59 +++++++++++++++++++++++++ .github/workflows/macos.yml | 4 +- .github/workflows/ubuntu.yml | 3 ++ cmake/cmake_celix/BundlePackaging.cmake | 28 ++++++------ 4 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/fuzzing.yml diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml new file mode 100644 index 000000000..3548624f3 --- /dev/null +++ b/.github/workflows/fuzzing.yml @@ -0,0 +1,59 @@ +name: Celix Fuzzing + +on: + push: + pull_request: + schedule: + - cron: '0 3 * * *' + +jobs: + fuzz-utils: + runs-on: ubuntu-22.04 + timeout-minutes: 30 + steps: + - name: Checkout source code + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0 + - name: Set up Python + uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c #v4.9.1 + with: + python-version: '3.x' + - name: Set Compiler Environment Variables + run: | + echo "CC=clang" >> $GITHUB_ENV + echo "CXX=clang++" >> $GITHUB_ENV + - name: Install Conan + run: pip install conan + - name: Cache Conan + uses: actions/cache@v3 + with: + path: ~/.conan2/p + key: ${{ runner.os }}-conan-${{ hashFiles('conanfile.py', 'libs/utils/**') }} + restore-keys: | + ${{ runner.os }}-conan- + - name: Setup Conan Profile + run: | + conan profile detect + - name: Conan install + run: conan install . --output-folder=build --build=missing -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" + - name: Conan build + run: conan build . --output-folder=build -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" + - name: Set fuzzer run time + id: set-runtime + run: | + if [[ "${{ github.event_name }}" == "schedule" ]]; then + echo "FUZZ_TIME=600" >> ${GITHUB_ENV} + else + echo "FUZZ_TIME=30" >> ${GITHUB_ENV} + fi + - name: Run properties fuzzer + run: | + source build/conanrun.sh + ./build/libs/utils/fuzzing/celix_properties_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/properties_corpus + - name: Run version fuzzer + run: | + source build/conanrun.sh + ./build/libs/utils/fuzzing/celix_version_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/version_corpus + - name: Run filter fuzzer + run: | + source build/conanrun.sh + ./build/libs/utils/fuzzing/celix_filter_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/filter_corpus diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index e0040b5e0..dd906497c 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -54,6 +54,7 @@ jobs: env: CONAN_BUILD_OPTIONS: | -o celix/*:enable_testing=True + -o celix/*:enable_benchmarking=True -o celix/*:enable_address_sanitizer=True -o celix/*:build_all=True -o celix/*:enable_cmake_warning_tests=True @@ -77,7 +78,7 @@ jobs: uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0 - name: Install dependencies run: | - brew install lcov jansson rapidjson libzip ccache ninja openssl@1.1 + brew install lcov jansson rapidjson libzip ccache ninja openssl@1.1 google-benchmark - name: Prepare ccache timestamp id: ccache_cache_timestamp run: | @@ -93,6 +94,7 @@ jobs: env: BUILD_OPTIONS: | -DENABLE_TESTING=ON + -DENABLE_BENCHMARKING=ON -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_TESTING_ON_CI=ON -DCMAKE_BUILD_TYPE=Release diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index a472b72e8..07de8bc08 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -77,6 +77,7 @@ jobs: CXX: ${{ matrix.compiler[1] }} CONAN_BUILD_OPTIONS: | -o celix:enable_testing=True + -o celix:enable_benchmarking=True -o celix:enable_address_sanitizer=True -o celix:build_all=True -o celix:enable_cmake_warning_tests=True @@ -120,6 +121,7 @@ jobs: libzip-dev \ libjansson-dev \ libcurl4-openssl-dev \ + libbenchmark-dev \ default-jdk \ cmake \ libffi-dev \ @@ -145,6 +147,7 @@ jobs: BUILD_OPTIONS: | -DBUILD_EXPERIMENTAL=ON -DENABLE_TESTING=ON + -DENABLE_BENCHMARKING=ON -DRSA_JSON_RPC=ON -DRSA_REMOTE_SERVICE_ADMIN_SHM_V2=ON -DENABLE_TESTING_ON_CI=ON diff --git a/cmake/cmake_celix/BundlePackaging.cmake b/cmake/cmake_celix/BundlePackaging.cmake index 9c1335e87..e181f052a 100644 --- a/cmake/cmake_celix/BundlePackaging.cmake +++ b/cmake/cmake_celix/BundlePackaging.cmake @@ -289,23 +289,23 @@ function(add_celix_bundle) ######################################################### ###### Packaging the bundle using using jar or zip and a content dir. Configuring dependencies ###### - if (JAR_COMMAND) + if (ZIP_COMMAND) + file(MAKE_DIRECTORY ${BUNDLE_CONTENT_DIR}) #Note needed because working_directory is bundle content dir add_custom_command(OUTPUT ${BUNDLE_FILE} - COMMAND ${CMAKE_COMMAND} -E make_directory ${BUNDLE_CONTENT_DIR} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json ${BUNDLE_CONTENT_DIR}/META-INF/MANIFEST.json - COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE} -C ${BUNDLE_CONTENT_DIR} . + COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE} * COMMENT "Packaging ${BUNDLE_TARGET_NAME}" DEPENDS ${BUNDLE_TARGET_NAME} "$" ${BUNDLE_GEN_DIR}/MANIFEST.json - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR} ) - elseif (ZIP_COMMAND) - file(MAKE_DIRECTORY ${BUNDLE_CONTENT_DIR}) #Note needed because working_directory is bundle content dir + elseif (JAR_COMMAND) add_custom_command(OUTPUT ${BUNDLE_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory ${BUNDLE_CONTENT_DIR} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json ${BUNDLE_CONTENT_DIR}/META-INF/MANIFEST.json - COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE} * + COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE} -C ${BUNDLE_CONTENT_DIR} . COMMENT "Packaging ${BUNDLE_TARGET_NAME}" DEPENDS ${BUNDLE_TARGET_NAME} "$" ${BUNDLE_GEN_DIR}/MANIFEST.json - WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) else () message(FATAL_ERROR "A jar or zip command is needed to jar/zip bundles") @@ -936,21 +936,21 @@ function(install_celix_bundle) set(BUNDLE_FILE_INSTALL "${BUNDLE_FILE}.install") get_target_property(BUNDLE_FILE_NAME ${BUNDLE} "BUNDLE_FILE_NAME") get_target_property(BUNDLE_GEN_DIR ${BUNDLE} "BUNDLE_GEN_DIR") - if (JAR_COMMAND) + if (ZIP_COMMAND) install(CODE "execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json META-INF/MANIFEST.json - COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} -C ${BUNDLE_CONTENT_DIR} . - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} . -i * + WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR} )" COMPONENT ${BUNDLE} ) - elseif (ZIP_COMMAND) + elseif (JAR_COMMAND) install(CODE "execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json META-INF/MANIFEST.json - COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} . -i * - WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR} + COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} -C ${BUNDLE_CONTENT_DIR} . + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} )" COMPONENT ${BUNDLE} ) From a60479b50f7d4be3a022080f9c059f362129dd36 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Thu, 14 Aug 2025 15:42:14 +0200 Subject: [PATCH 04/19] Add documentation for building benchmarks, fuzz testing, and running tests --- documents/README.md | 3 +- documents/building/README.md | 7 +++ documents/building/benchmarks.md | 74 ++++++++++++++++++++++++++++++ documents/building/fuzz_testing.md | 74 ++++++++++++++++++++++++++++++ documents/building/testing.md | 65 ++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 documents/building/benchmarks.md create mode 100644 documents/building/fuzz_testing.md create mode 100644 documents/building/testing.md diff --git a/documents/README.md b/documents/README.md index c174acbe7..d5f1c6667 100644 --- a/documents/README.md +++ b/documents/README.md @@ -81,8 +81,7 @@ bundles contains binaries depending on the stdlibc++ library. * Building * [Building and Installing Apache Celix](building/README.md) - * [Building and Developing Apache Celix with CLion](building/dev_celix_with_clion.md) -* C Patterns +≈* C Patterns * [Apache Celix C Patterns](c_patterns.md) * Utils * [Apache Celix Properties & Filter](properties_and_filter.md) diff --git a/documents/building/README.md b/documents/building/README.md index c64351003..7d01b8bb7 100644 --- a/documents/building/README.md +++ b/documents/building/README.md @@ -237,3 +237,10 @@ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../libs/pushstreams make -j sudo make install ``` + +# Further Reading + +- [Building with CLion](dev_celix_with_clion.md) +- [Building and Running Tests](testing.md) +- [Fuzz Testing](fuzz_testing.md) +- [Building and Running Benchmarks](benchmarks.md) diff --git a/documents/building/benchmarks.md b/documents/building/benchmarks.md new file mode 100644 index 000000000..d1061b3b8 --- /dev/null +++ b/documents/building/benchmarks.md @@ -0,0 +1,74 @@ +--- +title: Benchmarks in Apache Celix +--- + + + + +# Benchmarks in Apache Celix + +This document describes how to build and run benchmarks for Apache Celix. + +## Building Benchmarks + +Benchmarks can be built using the CMake option `ENABLE_BENCHMARKING` +The Apache Celix benchmarks uses Google benchmark library. + +To build benchmarks run: + +```sh +cmake -B build -DENABLE_BENCHMARKING=ON +cmake --build build +``` + +## Benchmarks + +The following benchmark executables are available after building the utils and framework benchmarks: + +**Utils Benchmarks:** +- `build/libs/utils/benchmark/celix_filter_benchmark` +- `build/libs/utils/benchmark/celix_long_hashmap_benchmark` +- `build/libs/utils/benchmark/celix_string_hashmap_benchmark` +- `build/libs/utils/benchmark/celix_utils_benchmark` + +**Framework Benchmarks:** +- `build/libs/framework/benchmark/celix_framework_benchmark` + +Paths may vary depending on your configuration and enabled options. + +## Running Benchmarks + +Benchmark executables are located in the `build` directory, typically under the relevant bundle or library subdirectory. To run a benchmark: + +```sh +./build/libs/utils/benchmarks/celix_utils_benchmark +## Command-Line Options +The benchmark executables accept standard Google Benchmark command-line options. +For example, to run only benchmarks matching a specific pattern and output results in JSON format: + +```bash +./build/libs/utils/benchmark/celix_filter_benchmark --benchmark_filter=complexFilter --benchmark_format=json +``` + +Replace `celix_utils_benchmark` and the filter pattern as needed. To see a list of supported command-line flags, run the benchmark executable with the `--help` option: + +```bash +./build/libs/utils/benchmarks/./celix_filter_benchmark --help +``` + +This will display all available Google Benchmark options. diff --git a/documents/building/fuzz_testing.md b/documents/building/fuzz_testing.md new file mode 100644 index 000000000..50f0abb21 --- /dev/null +++ b/documents/building/fuzz_testing.md @@ -0,0 +1,74 @@ +--- +title: Fuzz testing with libFuzzer +--- + + + +# Fuzz Testing with libFuzzer + +The utilities library contains fuzz targets that can be built with +[LLVM libFuzzer](https://llvm.org/docs/LibFuzzer.html). Fuzzing is +enabled when using the Clang compiler and the `UTILS_LIBFUZZER` CMake +option. + +## Building + +Configure CMake with Clang and enable the libFuzzer option: + +```bash +cmake \ + -G Ninja \ + -S . -B build \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ \ + -DENABLE_FUZZING=ON +``` + +Build the fuzzer executables: + +```bash +cmake --build build --parallel --target celix_properties_fuzzer celix_version_fuzzer celix_filter_fuzzer +``` + +## Corpus + +The `corpus` directories for the fuzzers contain a few seed inputs, which help guide the initial fuzzing process. +More files can be added to these directories to improve coverage. The fuzzer will automatically use all files in the +specified corpus directory as starting points for mutation and exploration. + +## Running +The resulting fuzzers accept standard libFuzzer command line options. For example, to run each fuzzer for 30 seconds +using the provided seed corpus and print coverage information: + +```bash +./build/libs/utils/celix_filter_fuzzer -max_total_time=30 -print_coverage=1 ./build/libs/utils/filter_corpus +``` + +Replace `celix_filter_fuzzer` and `filter_corpus` with the appropriate fuzzer executable and corpus directory as needed. +To see a list of supported command-line flags, run the fuzzer executable with the `-help=1` option. For example: + +```bash +./build/libs/utils/celix_filter_fuzzer -help=1 +``` + +This will display all available LibFuzzer options. + +## Continuous Fuzzing + +A GitHub Actions workflow runs the fuzzer periodically. The workflow +configuration can be found at `.github/workflows/fuzzing.yml`. diff --git a/documents/building/testing.md b/documents/building/testing.md new file mode 100644 index 000000000..557258ce0 --- /dev/null +++ b/documents/building/testing.md @@ -0,0 +1,65 @@ +--- +title: Testing Apache Celix +--- + + + +# Testing Apache Celix + +This document describes how to build and run tests for Apache Celix. + +## Building Tests + +Celix uses CMake and Google Test for its unit and integration tests. To build the tests, ensure you have all dependencies installed, then run: + +```sh +cmake -B build -DENABLE_TESTING=ON -DCMAKE_BUILD_TYPE=Debug +cmake --build build +``` + +```sh +#conan + +To enable AddressSanitizer (ASAN) when building tests, configure CMake with the `ENABLE_ASAN` option: + +```sh +cmake -B build -DENABLE_TESTING=ON -DENABLE_ADDRESS_SANITIZER=ON -DCMAKE_BUILD_TYPE=Debug +cmake --build build +``` + +This will build Apache Celix and its tests with ASAN enabled, helping to detect memory errors during test execution. + +## Running Tests + +After building, you can run all tests using CTest: + +```sh +ctest --output-on-failure --test-dir build +``` + +Or run a test for a specific subdir, e.g.: + +```sh +ctest --output-on-failure --test-dir build/bundles/shell +``` + +Or run a specific test binary directly from the `build` directory, e.g.: + +```sh +./build/bundles/components_ready_check/tests/components_ready_check_test +``` From e4a8a8317a6d99a10f85914500c3d17a66dd1aa2 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Fri, 15 Aug 2025 13:27:31 +0200 Subject: [PATCH 05/19] Remove C++ flag for macos, resulted in undefined symbols --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfb0c8c93..09e065ae8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,6 @@ endif () if(APPLE) set(CMAKE_MACOSX_RPATH 1) - set(CMAKE_CXX_FLAGS "-Wno-missing-template-arg-list-after-template-kw ${CMAKE_CXX_FLAGS}") endif() if(NOT APPLE) From a6f9ab1b64d25428496bb8950c7ac149142b3114 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Fri, 15 Aug 2025 13:29:26 +0200 Subject: [PATCH 06/19] Increase celix error buffer size for fuzz testing --- .github/workflows/fuzzing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 3548624f3..8528d17e0 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -36,7 +36,7 @@ jobs: - name: Conan install run: conan install . --output-folder=build --build=missing -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" - name: Conan build - run: conan build . --output-folder=build -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" + run: conan build . --output-folder=build -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" -o "celix/*:celix_err_buffer_size=5120" - name: Set fuzzer run time id: set-runtime run: | From b8e6e869bb4cab0dc2243422ca3805ecd637c812 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Mon, 15 Sep 2025 10:45:27 +0800 Subject: [PATCH 07/19] Eliminate clang warnings -Werror,-Wvla-cxx-extension --- libs/dfi/gtest/src/dyn_type_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/dfi/gtest/src/dyn_type_tests.cpp b/libs/dfi/gtest/src/dyn_type_tests.cpp index 84b4c9c6a..37e389022 100644 --- a/libs/dfi/gtest/src/dyn_type_tests.cpp +++ b/libs/dfi/gtest/src/dyn_type_tests.cpp @@ -37,8 +37,8 @@ extern "C" { int i; int j; int nrOfBurst = 10; - int burst = 50; - void *pointers[burst]; + void *pointers[50]; + int burst = sizeof(pointers) / sizeof(void *); for (j = 0; j < nrOfBurst; j += 1) { for (i = 0; i < burst ; i +=1 ) { pointers[i] = NULL; From b230f0e8fbadac11c36d08f039563434ef976851 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Mon, 15 Sep 2025 10:59:33 +0800 Subject: [PATCH 08/19] Add validation for enabling fuzzing with clang compiler only. --- conanfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conanfile.py b/conanfile.py index 577ee8c1c..e9b350e05 100644 --- a/conanfile.py +++ b/conanfile.py @@ -132,6 +132,9 @@ def validate(self): if self.options.build_rsa_discovery_zeroconf and self.settings.os != "Linux": raise ConanInvalidConfiguration("Celix build_rsa_discovery_zeroconf is only supported for Linux") + if self.options.enable_fuzzing and self.settings.compiler != "clang": + raise ConanInvalidConfiguration("Celix enable_fuzzing=True requires the 'clang' compiler") + self.validate_config_option_is_positive_number("celix_err_buffer_size") self.validate_config_option_is_positive_number("celix_utils_max_strlen") self.validate_config_option_is_positive_number("celix_properties_optimization_string_buffer_size") From c19772052f2b404eaef245b0d45488908620ad40 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Mon, 15 Sep 2025 11:03:50 +0800 Subject: [PATCH 09/19] Expand fuzzing validation to include Apple Clang. --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index e9b350e05..4b6251232 100644 --- a/conanfile.py +++ b/conanfile.py @@ -132,7 +132,7 @@ def validate(self): if self.options.build_rsa_discovery_zeroconf and self.settings.os != "Linux": raise ConanInvalidConfiguration("Celix build_rsa_discovery_zeroconf is only supported for Linux") - if self.options.enable_fuzzing and self.settings.compiler != "clang": + if self.options.enable_fuzzing and self.settings.compiler != "clang" and self.settings.compiler != "apple-clang": raise ConanInvalidConfiguration("Celix enable_fuzzing=True requires the 'clang' compiler") self.validate_config_option_is_positive_number("celix_err_buffer_size") From 4d3af6c206aa00809828b69d00fdb3e17bbd61e9 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Mon, 15 Sep 2025 11:36:56 +0800 Subject: [PATCH 10/19] Refactor `benchmark` dependency to `test_requires` when `enable_benchmarking` is set. --- conanfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 4b6251232..c018ebc25 100644 --- a/conanfile.py +++ b/conanfile.py @@ -160,6 +160,8 @@ def build_requirements(self): self.test_requires("gtest/1.10.0") if self.options.enable_ccache: self.build_requires("ccache/4.7.4") + if self.options.enable_benchmarking: + self.test_requires("benchmark/[>=1.6.2]") def configure(self): # copy options to options, fill in defaults if not set @@ -366,8 +368,6 @@ def requirements(self): self.requires("zlib/1.2.13", override=True) if self.options.build_event_admin_remote_provider_mqtt: self.requires("mosquitto/[>=2.0.3 <3.0.0]") - if self.options.enable_benchmarking: - self.requires("benchmark/[>=1.6.2]") self.validate() def generate(self): From fe77a13a65f84fc75e4c8ce9bbc4c7be6c34f0e2 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Mon, 15 Sep 2025 11:47:16 +0800 Subject: [PATCH 11/19] Fix formatting issue in README under "C Patterns" section. --- documents/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documents/README.md b/documents/README.md index d5f1c6667..0fee3cc46 100644 --- a/documents/README.md +++ b/documents/README.md @@ -81,7 +81,7 @@ bundles contains binaries depending on the stdlibc++ library. * Building * [Building and Installing Apache Celix](building/README.md) -≈* C Patterns +* C Patterns * [Apache Celix C Patterns](c_patterns.md) * Utils * [Apache Celix Properties & Filter](properties_and_filter.md) From 7b15c7547031ffd2c27476d3d991c2ecc8f9c132 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 9 Dec 2025 21:34:43 +0100 Subject: [PATCH 12/19] Update to actions/cache 4.3.0 --- .github/workflows/fuzzing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 8528d17e0..7f587f40f 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -24,7 +24,7 @@ jobs: - name: Install Conan run: pip install conan - name: Cache Conan - uses: actions/cache@v3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0 with: path: ~/.conan2/p key: ${{ runner.os }}-conan-${{ hashFiles('conanfile.py', 'libs/utils/**') }} From 1f61d321fde7121ecfa5a698a22d957394fac7c9 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 9 Dec 2025 21:43:17 +0100 Subject: [PATCH 13/19] Add asan and ubsan for fuzz testing builds --- .github/workflows/fuzzing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 7f587f40f..242b47567 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -34,9 +34,9 @@ jobs: run: | conan profile detect - name: Conan install - run: conan install . --output-folder=build --build=missing -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" + run: conan install . --output-folder=build --build=missing -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" -o "celix/*:enable_address_sanitizer=True" -o "celix/*:enable_undefined_sanitizer=True" - name: Conan build - run: conan build . --output-folder=build -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" -o "celix/*:celix_err_buffer_size=5120" + run: conan build . --output-folder=build -o "celix/*:build_utils=True" -o "celix/*:enable_fuzzing=True" -o "celix/*:enable_address_sanitizer=True" -o "celix/*:enable_undefined_sanitizer=True" -o "celix/*:celix_err_buffer_size=5120" - name: Set fuzzer run time id: set-runtime run: | From f6ffa196717cf5592d6eaa455854c3a06fedf5c7 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 9 Dec 2025 22:35:18 +0100 Subject: [PATCH 14/19] Apply linux clang asan libpath issue for fuzz testing --- cmake/celix_project/CelixProject.cmake | 44 ++++++++++++++------------ libs/utils/fuzzing/CMakeLists.txt | 4 +++ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/cmake/celix_project/CelixProject.cmake b/cmake/celix_project/CelixProject.cmake index 0f3132744..720617b09 100644 --- a/cmake/celix_project/CelixProject.cmake +++ b/cmake/celix_project/CelixProject.cmake @@ -24,6 +24,29 @@ mark_as_advanced(CLEAR ENABLE_ADDRESS_SANITIZER) mark_as_advanced(CLEAR ENABLE_UNDEFINED_SANITIZER) mark_as_advanced(CLEAR ENABLE_THREAD_SANITIZER) +function(celix_fix_linux_clang_asan_libpath) + # Fix a linux clang deficiency where the ASan runtime library is not found automatically + # Find the ASan runtime library path and set RPATH + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} --print-file-name libclang_rt.asan-x86_64.so + OUTPUT_VARIABLE ASAN_LIB_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE ASAN_FIND_RESULT + ERROR_QUIET # Avoid printing errors if the command fails during configuration + ) + + if (ASAN_FIND_RESULT EQUAL 0 AND EXISTS "${ASAN_LIB_PATH}") + get_filename_component(ASAN_LIB_DIR ${ASAN_LIB_PATH} DIRECTORY) + message(STATUS "Setting ASan RPATH to: ${ASAN_LIB_DIR}") + set(ASAN_RPATH_FLAG "-Wl,-rpath,${ASAN_LIB_DIR}") + # Append to executable, shared library, and module linker flags + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") + else() + message(WARNING "Could not determine path for libclang_rt.asan-x86_64.so using ${CMAKE_CXX_COMPILER}. ASan RPATH not set automatically.") + endif() +endfunction() + if (ENABLE_ADDRESS_SANITIZER) if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") set(CMAKE_C_FLAGS "-DCELIX_ASAN_ENABLED ${CMAKE_C_FLAGS}") @@ -33,26 +56,7 @@ if (ENABLE_ADDRESS_SANITIZER) set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address ${CMAKE_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=address ${CMAKE_SHARED_LINKER_FLAGS}") else () - # Fix a linux clang deficiency where the ASan runtime library is not found automatically - # Find the ASan runtime library path and set RPATH - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} --print-file-name libclang_rt.asan-x86_64.so - OUTPUT_VARIABLE ASAN_LIB_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE ASAN_FIND_RESULT - ERROR_QUIET # Avoid printing errors if the command fails during configuration - ) - - if (ASAN_FIND_RESULT EQUAL 0 AND EXISTS "${ASAN_LIB_PATH}") - get_filename_component(ASAN_LIB_DIR ${ASAN_LIB_PATH} DIRECTORY) - message(STATUS "Setting ASan RPATH to: ${ASAN_LIB_DIR}") - set(ASAN_RPATH_FLAG "-Wl,-rpath,${ASAN_LIB_DIR}") - # Append to executable, shared library, and module linker flags - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") - else() - message(WARNING "Could not determine path for libclang_rt.asan-x86_64.so using ${CMAKE_CXX_COMPILER}. ASan RPATH not set automatically.") - endif() + celix_fix_linux_clang_asan_libpath() endif () elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_C_FLAGS "-DCELIX_ASAN_ENABLED ${CMAKE_C_FLAGS}") diff --git a/libs/utils/fuzzing/CMakeLists.txt b/libs/utils/fuzzing/CMakeLists.txt index 90b9eefaf..978a6b956 100644 --- a/libs/utils/fuzzing/CMakeLists.txt +++ b/libs/utils/fuzzing/CMakeLists.txt @@ -14,6 +14,10 @@ # limitations under the License. +if (LINUX) + celix_fix_linux_clang_asan_libpath() +endif () + 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) From 5ee1a96e6d2ca382f404d8fd125df63e8bc69719 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 9 Dec 2025 22:39:07 +0100 Subject: [PATCH 15/19] change cmake function to macro --- cmake/celix_project/CelixProject.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/celix_project/CelixProject.cmake b/cmake/celix_project/CelixProject.cmake index 720617b09..893130d8a 100644 --- a/cmake/celix_project/CelixProject.cmake +++ b/cmake/celix_project/CelixProject.cmake @@ -24,7 +24,7 @@ mark_as_advanced(CLEAR ENABLE_ADDRESS_SANITIZER) mark_as_advanced(CLEAR ENABLE_UNDEFINED_SANITIZER) mark_as_advanced(CLEAR ENABLE_THREAD_SANITIZER) -function(celix_fix_linux_clang_asan_libpath) +macro(celix_fix_linux_clang_asan_libpath) # Fix a linux clang deficiency where the ASan runtime library is not found automatically # Find the ASan runtime library path and set RPATH execute_process( @@ -45,7 +45,7 @@ function(celix_fix_linux_clang_asan_libpath) else() message(WARNING "Could not determine path for libclang_rt.asan-x86_64.so using ${CMAKE_CXX_COMPILER}. ASan RPATH not set automatically.") endif() -endfunction() +endmacro()() if (ENABLE_ADDRESS_SANITIZER) if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") From 3878ee8d6281bd11f35cdf0416bb3037c4fcdad3 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Tue, 9 Dec 2025 22:42:28 +0100 Subject: [PATCH 16/19] fix cmake error --- cmake/celix_project/CelixProject.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/celix_project/CelixProject.cmake b/cmake/celix_project/CelixProject.cmake index 893130d8a..9ebc47658 100644 --- a/cmake/celix_project/CelixProject.cmake +++ b/cmake/celix_project/CelixProject.cmake @@ -45,7 +45,7 @@ macro(celix_fix_linux_clang_asan_libpath) else() message(WARNING "Could not determine path for libclang_rt.asan-x86_64.so using ${CMAKE_CXX_COMPILER}. ASan RPATH not set automatically.") endif() -endmacro()() +endmacro() if (ENABLE_ADDRESS_SANITIZER) if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") From 0cbee96c0ad3a199076d61927021a37acb73bd22 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 14 Dec 2025 17:01:28 +0100 Subject: [PATCH 17/19] Use LD_PRELOAD for fuzz testing action --- .github/workflows/fuzzing.yml | 3 ++ cmake/celix_project/CelixProject.cmake | 68 ++++++++++++-------------- libs/utils/fuzzing/CMakeLists.txt | 16 +++--- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 242b47567..2aaf71c7f 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -48,12 +48,15 @@ jobs: - name: Run properties fuzzer run: | source build/conanrun.sh + export LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./build/libs/utils/fuzzing/celix_properties_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/properties_corpus - name: Run version fuzzer run: | source build/conanrun.sh + export LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./build/libs/utils/fuzzing/celix_version_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/version_corpus - name: Run filter fuzzer run: | source build/conanrun.sh + export LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./build/libs/utils/fuzzing/celix_filter_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/filter_corpus diff --git a/cmake/celix_project/CelixProject.cmake b/cmake/celix_project/CelixProject.cmake index 9ebc47658..8f231a2dd 100644 --- a/cmake/celix_project/CelixProject.cmake +++ b/cmake/celix_project/CelixProject.cmake @@ -24,55 +24,51 @@ mark_as_advanced(CLEAR ENABLE_ADDRESS_SANITIZER) mark_as_advanced(CLEAR ENABLE_UNDEFINED_SANITIZER) mark_as_advanced(CLEAR ENABLE_THREAD_SANITIZER) -macro(celix_fix_linux_clang_asan_libpath) - # Fix a linux clang deficiency where the ASan runtime library is not found automatically - # Find the ASan runtime library path and set RPATH - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} --print-file-name libclang_rt.asan-x86_64.so - OUTPUT_VARIABLE ASAN_LIB_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE ASAN_FIND_RESULT - ERROR_QUIET # Avoid printing errors if the command fails during configuration - ) - - if (ASAN_FIND_RESULT EQUAL 0 AND EXISTS "${ASAN_LIB_PATH}") - get_filename_component(ASAN_LIB_DIR ${ASAN_LIB_PATH} DIRECTORY) - message(STATUS "Setting ASan RPATH to: ${ASAN_LIB_DIR}") - set(ASAN_RPATH_FLAG "-Wl,-rpath,${ASAN_LIB_DIR}") - # Append to executable, shared library, and module linker flags - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") - else() - message(WARNING "Could not determine path for libclang_rt.asan-x86_64.so using ${CMAKE_CXX_COMPILER}. ASan RPATH not set automatically.") - endif() -endmacro() - if (ENABLE_ADDRESS_SANITIZER) + set(UBSAN_SAN "") + if (ENABLE_UNDEFINED_SANITIZER) + set(UBSAN_SAN "undefined,") + endif () if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") set(CMAKE_C_FLAGS "-DCELIX_ASAN_ENABLED ${CMAKE_C_FLAGS}") - set(CMAKE_C_FLAGS "-shared-libasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}") - set(CMAKE_CXX_FLAGS "-shared-libasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}") + set(CMAKE_C_FLAGS "-shared-libasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS "-shared-libasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}") if (APPLE) - set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address ${CMAKE_EXE_LINKER_FLAGS}") - set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=address ${CMAKE_SHARED_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=${UBSAN_SAN}address ${CMAKE_EXE_LINKER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=${UBSAN_SAN}address ${CMAKE_SHARED_LINKER_FLAGS}") else () - celix_fix_linux_clang_asan_libpath() + # Fix a linux clang deficiency where the ASan runtime library is not found automatically + # Find the ASan runtime library path and set RPATH + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} --print-file-name libclang_rt.asan-x86_64.so + OUTPUT_VARIABLE ASAN_LIB_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE ASAN_FIND_RESULT + ERROR_QUIET # Avoid printing errors if the command fails during configuration + ) + + if (ASAN_FIND_RESULT EQUAL 0 AND EXISTS "${ASAN_LIB_PATH}") + get_filename_component(ASAN_LIB_DIR ${ASAN_LIB_PATH} DIRECTORY) + message(STATUS "Setting ASan RPATH to: ${ASAN_LIB_DIR}") + set(ASAN_RPATH_FLAG "-Wl,-rpath,${ASAN_LIB_DIR}") + # Append to executable, shared library, and module linker flags + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_RPATH_FLAG}") + else() + message(WARNING "Could not determine path for libclang_rt.asan-x86_64.so using ${CMAKE_CXX_COMPILER}. ASan RPATH not set automatically.") + endif() endif () elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_C_FLAGS "-DCELIX_ASAN_ENABLED ${CMAKE_C_FLAGS}") - set(CMAKE_C_FLAGS "-lasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}") - set(CMAKE_CXX_FLAGS "-lasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}") + set(CMAKE_C_FLAGS "-lasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS "-lasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}") else () message(WARNING "Address sanitizer is not supported for ${CMAKE_C_COMPILER_ID}") endif () -endif() - -if (ENABLE_UNDEFINED_SANITIZER) +elseif (ENABLE_UNDEFINED_SANITIZER) set(CMAKE_C_FLAGS "-fsanitize=undefined ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "-fsanitize=undefined ${CMAKE_CXX_FLAGS}") -endif() - -if (ENABLE_THREAD_SANITIZER) +elseif (ENABLE_THREAD_SANITIZER) set(CMAKE_C_FLAGS "-fsanitize=thread ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "-fsanitize=thread ${CMAKE_CXX_FLAGS}") endif() diff --git a/libs/utils/fuzzing/CMakeLists.txt b/libs/utils/fuzzing/CMakeLists.txt index 978a6b956..571f06ef2 100644 --- a/libs/utils/fuzzing/CMakeLists.txt +++ b/libs/utils/fuzzing/CMakeLists.txt @@ -14,24 +14,20 @@ # limitations under the License. -if (LINUX) - celix_fix_linux_clang_asan_libpath() -endif () - 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) +target_compile_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) +target_link_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer,undefined,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) +target_compile_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) +target_link_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer,undefined,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) +target_compile_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) +target_link_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) add_custom_command(TARGET celix_properties_fuzzer POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory From 2eb5f691b5c346b2ac11103505cec5c3491e7d32 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 14 Dec 2025 17:12:03 +0100 Subject: [PATCH 18/19] Enable ubsan with asan for linux ci --- .github/workflows/ubuntu.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 07de8bc08..dc0964f4a 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -79,6 +79,7 @@ jobs: -o celix:enable_testing=True -o celix:enable_benchmarking=True -o celix:enable_address_sanitizer=True + -o celix:enable_undefined_sanitizer=True -o celix:build_all=True -o celix:enable_cmake_warning_tests=True -o celix:enable_testing_on_ci=True From 9344b8983e9b2c3965c009276bd8a40f3d65824d Mon Sep 17 00:00:00 2001 From: PengZheng Date: Mon, 15 Dec 2025 20:16:47 +0800 Subject: [PATCH 19/19] Remove LD_PRELOAD for fuzz testing and simplify sanitizer options. --- .github/workflows/fuzzing.yml | 3 --- libs/utils/CMakeLists.txt | 3 +-- libs/utils/fuzzing/CMakeLists.txt | 15 +++++++++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index 2aaf71c7f..242b47567 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -48,15 +48,12 @@ jobs: - name: Run properties fuzzer run: | source build/conanrun.sh - export LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./build/libs/utils/fuzzing/celix_properties_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/properties_corpus - name: Run version fuzzer run: | source build/conanrun.sh - export LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./build/libs/utils/fuzzing/celix_version_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/version_corpus - name: Run filter fuzzer run: | source build/conanrun.sh - export LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./build/libs/utils/fuzzing/celix_filter_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/filter_corpus diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index cb29f8f60..e28317b49 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -138,8 +138,7 @@ if (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_compile_options(utils_cuf PRIVATE -fsanitize=fuzzer) target_link_options(utils_cuf PRIVATE -Wl,--gc-sections) add_subdirectory(fuzzing) diff --git a/libs/utils/fuzzing/CMakeLists.txt b/libs/utils/fuzzing/CMakeLists.txt index 571f06ef2..a7e248e35 100644 --- a/libs/utils/fuzzing/CMakeLists.txt +++ b/libs/utils/fuzzing/CMakeLists.txt @@ -13,21 +13,24 @@ # See the License for the specific language governing permissions and # limitations under the License. +if (ENABLE_ADDRESS_SANITIZER OR ENABLE_UNDEFINED_SANITIZER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libsan") +endif () 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,undefined,address) -target_link_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) +target_compile_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer) +target_link_options(celix_properties_fuzzer PRIVATE -fsanitize=fuzzer) 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,undefined,address) -target_link_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) +target_compile_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer) +target_link_options(celix_version_fuzzer PRIVATE -fsanitize=fuzzer) 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,undefined,address) -target_link_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer,undefined,address) +target_compile_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer) +target_link_options(celix_filter_fuzzer PRIVATE -fsanitize=fuzzer) add_custom_command(TARGET celix_properties_fuzzer POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory