Skip to content

Commit 7160174

Browse files
pnoltesPengZheng
andauthored
Feature/add fuzzing (#799)
Add fuzz testing * Also improves benchmark setup * Add fuzzing workflow and enable benchmarking options in CI configurations * Add documentation for building benchmarks, fuzz testing, and running tests * Remove C++ flag for macos, resulted in undefined symbols * Increase celix error buffer size for fuzz testing * Eliminate clang warnings -Werror,-Wvla-cxx-extension * Refactor `benchmark` dependency to `test_requires` when `enable_benchmarking` is set. * Fix formatting issue in README under "C Patterns" section. * Update to actions/cache 4.3.0 * Add asan and ubsan for fuzz testing builds * Enable ubsan with asan for linux ci --------- Co-authored-by: PengZheng <howtofly@gmail.com>
1 parent c6d0e2a commit 7160174

File tree

25 files changed

+484
-44
lines changed

25 files changed

+484
-44
lines changed

.github/workflows/fuzzing.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Celix Fuzzing
2+
3+
on:
4+
push:
5+
pull_request:
6+
schedule:
7+
- cron: '0 3 * * *'
8+
9+
jobs:
10+
fuzz-utils:
11+
runs-on: ubuntu-22.04
12+
timeout-minutes: 30
13+
steps:
14+
- name: Checkout source code
15+
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0
16+
- name: Set up Python
17+
uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c #v4.9.1
18+
with:
19+
python-version: '3.x'
20+
- name: Set Compiler Environment Variables
21+
run: |
22+
echo "CC=clang" >> $GITHUB_ENV
23+
echo "CXX=clang++" >> $GITHUB_ENV
24+
- name: Install Conan
25+
run: pip install conan
26+
- name: Cache Conan
27+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 #v4.3.0
28+
with:
29+
path: ~/.conan2/p
30+
key: ${{ runner.os }}-conan-${{ hashFiles('conanfile.py', 'libs/utils/**') }}
31+
restore-keys: |
32+
${{ runner.os }}-conan-
33+
- name: Setup Conan Profile
34+
run: |
35+
conan profile detect
36+
- name: Conan install
37+
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"
38+
- name: Conan build
39+
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"
40+
- name: Set fuzzer run time
41+
id: set-runtime
42+
run: |
43+
if [[ "${{ github.event_name }}" == "schedule" ]]; then
44+
echo "FUZZ_TIME=600" >> ${GITHUB_ENV}
45+
else
46+
echo "FUZZ_TIME=30" >> ${GITHUB_ENV}
47+
fi
48+
- name: Run properties fuzzer
49+
run: |
50+
source build/conanrun.sh
51+
./build/libs/utils/fuzzing/celix_properties_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/properties_corpus
52+
- name: Run version fuzzer
53+
run: |
54+
source build/conanrun.sh
55+
./build/libs/utils/fuzzing/celix_version_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/version_corpus
56+
- name: Run filter fuzzer
57+
run: |
58+
source build/conanrun.sh
59+
./build/libs/utils/fuzzing/celix_filter_fuzzer -max_total_time=$FUZZ_TIME ./build/libs/utils/fuzzing/filter_corpus

.github/workflows/macos.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ jobs:
5656
env:
5757
CONAN_BUILD_OPTIONS: |
5858
-o celix/*:enable_testing=True
59+
-o celix/*:enable_benchmarking=True
5960
-o celix/*:enable_address_sanitizer=True
6061
-o celix/*:build_all=True
6162
-o celix/*:enable_cmake_warning_tests=True
@@ -79,7 +80,7 @@ jobs:
7980
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0
8081
- name: Install dependencies
8182
run: |
82-
brew install lcov jansson rapidjson libzip ccache ninja openssl@1.1
83+
brew install lcov jansson rapidjson libzip ccache ninja openssl@1.1 google-benchmark
8384
- name: Prepare ccache timestamp
8485
id: ccache_cache_timestamp
8586
run: |
@@ -95,6 +96,7 @@ jobs:
9596
env:
9697
BUILD_OPTIONS: |
9798
-DENABLE_TESTING=ON
99+
-DENABLE_BENCHMARKING=ON
98100
-DENABLE_ADDRESS_SANITIZER=ON
99101
-DENABLE_TESTING_ON_CI=ON
100102
-DCMAKE_BUILD_TYPE=Release

.github/workflows/ubuntu.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ jobs:
7777
CXX: ${{ matrix.compiler[1] }}
7878
CONAN_BUILD_OPTIONS: |
7979
-o celix:enable_testing=True
80+
-o celix:enable_benchmarking=True
8081
-o celix:enable_address_sanitizer=True
82+
-o celix:enable_undefined_sanitizer=True
8183
-o celix:build_all=True
8284
-o celix:enable_cmake_warning_tests=True
8385
-o celix:enable_testing_on_ci=True
@@ -120,6 +122,7 @@ jobs:
120122
libzip-dev \
121123
libjansson-dev \
122124
libcurl4-openssl-dev \
125+
libbenchmark-dev \
123126
default-jdk \
124127
cmake \
125128
libffi-dev \
@@ -145,6 +148,7 @@ jobs:
145148
BUILD_OPTIONS: |
146149
-DBUILD_EXPERIMENTAL=ON
147150
-DENABLE_TESTING=ON
151+
-DENABLE_BENCHMARKING=ON
148152
-DRSA_JSON_RPC=ON
149153
-DRSA_REMOTE_SERVICE_ADMIN_SHM_V2=ON
150154
-DENABLE_TESTING_ON_CI=ON

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ endif ()
168168
option(ENABLE_CMAKE_WARNING_TESTS "Enable cmake warning tests to test warning prints" OFF)
169169
option(ENABLE_TESTING_ON_CI "Whether to enable testing on CI. This influence allowed timing errors during unit tests" OFF)
170170
option(ENABLE_DEPRECATED_WARNINGS "Enable compiler warnings for usage of deprecated functionality" OFF)
171+
option(ENABLE_FUZZING "Enable fuzz testing, using LibFuzzer" OFF) #Note support for LibFuzzer is built-in for Clang
172+
option(ENABLE_BENCHMARKING "Enable benchmarking, using Google Benchmark" OFF)
171173

172174
if (NOT ENABLE_DEPRECATED_WARNINGS)
173175
set(CMAKE_C_FLAGS "-Wno-deprecated-declarations ${CMAKE_C_FLAGS}")

cmake/celix_project/CelixProject.cmake

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ mark_as_advanced(CLEAR ENABLE_UNDEFINED_SANITIZER)
2525
mark_as_advanced(CLEAR ENABLE_THREAD_SANITIZER)
2626

2727
if (ENABLE_ADDRESS_SANITIZER)
28+
set(UBSAN_SAN "")
29+
if (ENABLE_UNDEFINED_SANITIZER)
30+
set(UBSAN_SAN "undefined,")
31+
endif ()
2832
if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
2933
set(CMAKE_C_FLAGS "-DCELIX_ASAN_ENABLED ${CMAKE_C_FLAGS}")
30-
set(CMAKE_C_FLAGS "-shared-libasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}")
31-
set(CMAKE_CXX_FLAGS "-shared-libasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}")
34+
set(CMAKE_C_FLAGS "-shared-libasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}")
35+
set(CMAKE_CXX_FLAGS "-shared-libasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}")
3236
if (APPLE)
33-
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address ${CMAKE_EXE_LINKER_FLAGS}")
34-
set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=address ${CMAKE_SHARED_LINKER_FLAGS}")
37+
set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=${UBSAN_SAN}address ${CMAKE_EXE_LINKER_FLAGS}")
38+
set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=${UBSAN_SAN}address ${CMAKE_SHARED_LINKER_FLAGS}")
3539
else ()
3640
# Fix a linux clang deficiency where the ASan runtime library is not found automatically
3741
# Find the ASan runtime library path and set RPATH
@@ -56,19 +60,15 @@ if (ENABLE_ADDRESS_SANITIZER)
5660
endif ()
5761
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
5862
set(CMAKE_C_FLAGS "-DCELIX_ASAN_ENABLED ${CMAKE_C_FLAGS}")
59-
set(CMAKE_C_FLAGS "-lasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}")
60-
set(CMAKE_CXX_FLAGS "-lasan -fsanitize=address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}")
63+
set(CMAKE_C_FLAGS "-lasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_C_FLAGS}")
64+
set(CMAKE_CXX_FLAGS "-lasan -fsanitize=${UBSAN_SAN}address -fno-omit-frame-pointer ${CMAKE_CXX_FLAGS}")
6165
else ()
6266
message(WARNING "Address sanitizer is not supported for ${CMAKE_C_COMPILER_ID}")
6367
endif ()
64-
endif()
65-
66-
if (ENABLE_UNDEFINED_SANITIZER)
68+
elseif (ENABLE_UNDEFINED_SANITIZER)
6769
set(CMAKE_C_FLAGS "-fsanitize=undefined ${CMAKE_C_FLAGS}")
6870
set(CMAKE_CXX_FLAGS "-fsanitize=undefined ${CMAKE_CXX_FLAGS}")
69-
endif()
70-
71-
if (ENABLE_THREAD_SANITIZER)
71+
elseif (ENABLE_THREAD_SANITIZER)
7272
set(CMAKE_C_FLAGS "-fsanitize=thread ${CMAKE_C_FLAGS}")
7373
set(CMAKE_CXX_FLAGS "-fsanitize=thread ${CMAKE_CXX_FLAGS}")
7474
endif()

cmake/cmake_celix/BundlePackaging.cmake

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -287,23 +287,23 @@ function(add_celix_bundle)
287287
#########################################################
288288

289289
###### Packaging the bundle using using jar or zip and a content dir. Configuring dependencies ######
290-
if (JAR_COMMAND)
290+
if (ZIP_COMMAND)
291+
file(MAKE_DIRECTORY ${BUNDLE_CONTENT_DIR}) #Note needed because working_directory is bundle content dir
291292
add_custom_command(OUTPUT ${BUNDLE_FILE}
292-
COMMAND ${CMAKE_COMMAND} -E make_directory ${BUNDLE_CONTENT_DIR}
293293
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json ${BUNDLE_CONTENT_DIR}/META-INF/MANIFEST.json
294-
COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE} -C ${BUNDLE_CONTENT_DIR} .
294+
COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE} *
295295
COMMENT "Packaging ${BUNDLE_TARGET_NAME}"
296296
DEPENDS ${BUNDLE_TARGET_NAME} "$<TARGET_PROPERTY:${BUNDLE_TARGET_NAME},BUNDLE_DEPEND_TARGETS>" ${BUNDLE_GEN_DIR}/MANIFEST.json
297-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
297+
WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR}
298298
)
299-
elseif (ZIP_COMMAND)
300-
file(MAKE_DIRECTORY ${BUNDLE_CONTENT_DIR}) #Note needed because working_directory is bundle content dir
299+
elseif (JAR_COMMAND)
301300
add_custom_command(OUTPUT ${BUNDLE_FILE}
301+
COMMAND ${CMAKE_COMMAND} -E make_directory ${BUNDLE_CONTENT_DIR}
302302
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json ${BUNDLE_CONTENT_DIR}/META-INF/MANIFEST.json
303-
COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE} *
303+
COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE} -C ${BUNDLE_CONTENT_DIR} .
304304
COMMENT "Packaging ${BUNDLE_TARGET_NAME}"
305305
DEPENDS ${BUNDLE_TARGET_NAME} "$<TARGET_PROPERTY:${BUNDLE_TARGET_NAME},BUNDLE_DEPEND_TARGETS>" ${BUNDLE_GEN_DIR}/MANIFEST.json
306-
WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR}
306+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
307307
)
308308
else ()
309309
message(FATAL_ERROR "A jar or zip command is needed to jar/zip bundles")
@@ -934,21 +934,21 @@ function(install_celix_bundle)
934934
set(BUNDLE_FILE_INSTALL "${BUNDLE_FILE}.install")
935935
get_target_property(BUNDLE_FILE_NAME ${BUNDLE} "BUNDLE_FILE_NAME")
936936
get_target_property(BUNDLE_GEN_DIR ${BUNDLE} "BUNDLE_GEN_DIR")
937-
if (JAR_COMMAND)
937+
if (ZIP_COMMAND)
938938
install(CODE
939939
"execute_process(
940940
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json META-INF/MANIFEST.json
941-
COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} -C ${BUNDLE_CONTENT_DIR} .
942-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
941+
COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} . -i *
942+
WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR}
943943
)"
944944
COMPONENT ${BUNDLE}
945945
)
946-
elseif (ZIP_COMMAND)
946+
elseif (JAR_COMMAND)
947947
install(CODE
948948
"execute_process(
949949
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUNDLE_GEN_DIR}/MANIFEST.json META-INF/MANIFEST.json
950-
COMMAND ${ZIP_COMMAND} ${CELIX_ZIP_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} . -i *
951-
WORKING_DIRECTORY ${BUNDLE_CONTENT_DIR}
950+
COMMAND ${JAR_COMMAND} ${CELIX_JAR_COMMAND_ARGUMENTS} ${BUNDLE_FILE_INSTALL} -C ${BUNDLE_CONTENT_DIR} .
951+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
952952
)"
953953
COMPONENT ${BUNDLE}
954954
)

conanfile.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class CelixConan(ConanFile):
4747
"enable_address_sanitizer": False,
4848
"enable_undefined_sanitizer": False,
4949
"enable_thread_sanitizer": False,
50+
"enable_fuzzing": False,
51+
"enable_benchmarking": False,
5052
"install_find_modules": False,
5153
"build_all": False,
5254
"build_http_admin": False,
@@ -130,6 +132,9 @@ def validate(self):
130132
if self.options.build_rsa_discovery_zeroconf and self.settings.os != "Linux":
131133
raise ConanInvalidConfiguration("Celix build_rsa_discovery_zeroconf is only supported for Linux")
132134

135+
if self.options.enable_fuzzing and self.settings.compiler != "clang" and self.settings.compiler != "apple-clang":
136+
raise ConanInvalidConfiguration("Celix enable_fuzzing=True requires the 'clang' compiler")
137+
133138
self.validate_config_option_is_positive_number("celix_err_buffer_size")
134139
self.validate_config_option_is_positive_number("celix_utils_max_strlen")
135140
self.validate_config_option_is_positive_number("celix_properties_optimization_string_buffer_size")
@@ -145,12 +150,18 @@ def package_id(self):
145150
del self.info.options.enable_testing_on_ci
146151
del self.info.options.enable_ccache
147152
del self.info.options.enable_deprecated_warnings
153+
del self.info.options.enable_testing
154+
del self.info.options.enable_benchmarking
155+
del self.info.options.enable_fuzzing
156+
del self.info.options.enable_code_coverage
148157

149158
def build_requirements(self):
150159
if self.options.enable_testing:
151160
self.test_requires("gtest/1.10.0")
152161
if self.options.enable_ccache:
153162
self.build_requires("ccache/4.7.4")
163+
if self.options.enable_benchmarking:
164+
self.test_requires("benchmark/[>=1.6.2]")
154165

155166
def configure(self):
156167
# copy options to options, fill in defaults if not set
@@ -308,6 +319,8 @@ def configure(self):
308319
self.options['openssl'].shared = True
309320
if self.options.enable_testing:
310321
self.options['gtest'].shared = True
322+
if self.options.enable_benchmarking:
323+
self.options['benchmark'].shared = True
311324
if (self.options.build_rsa_discovery_common
312325
or (self.options.build_rsa_remote_service_admin_dfi and self.options.enable_testing)):
313326
self.options['libxml2'].shared = True

documents/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ bundles contains binaries depending on the stdlibc++ library.
8181

8282
* Building
8383
* [Building and Installing Apache Celix](building/README.md)
84-
* [Building and Developing Apache Celix with CLion](building/dev_celix_with_clion.md)
8584
* C Patterns
8685
* [Apache Celix C Patterns](c_patterns.md)
8786
* Utils

documents/building/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,10 @@ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../libs/pushstreams
237237
make -j
238238
sudo make install
239239
```
240+
241+
# Further Reading
242+
243+
- [Building with CLion](dev_celix_with_clion.md)
244+
- [Building and Running Tests](testing.md)
245+
- [Fuzz Testing](fuzz_testing.md)
246+
- [Building and Running Benchmarks](benchmarks.md)

documents/building/benchmarks.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
title: Benchmarks in Apache Celix
3+
---
4+
5+
<!--
6+
Licensed to the Apache Software Foundation (ASF) under one or more
7+
contributor license agreements. See the NOTICE file distributed with
8+
this work for additional information regarding copyright ownership.
9+
The ASF licenses this file to You under the Apache License, Version 2.0
10+
(the "License"); you may not use this file except in compliance with
11+
the License. You may obtain a copy of the License at
12+
13+
http://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
-->
21+
22+
23+
# Benchmarks in Apache Celix
24+
25+
This document describes how to build and run benchmarks for Apache Celix.
26+
27+
## Building Benchmarks
28+
29+
Benchmarks can be built using the CMake option `ENABLE_BENCHMARKING`
30+
The Apache Celix benchmarks uses Google benchmark library.
31+
32+
To build benchmarks run:
33+
34+
```sh
35+
cmake -B build -DENABLE_BENCHMARKING=ON
36+
cmake --build build
37+
```
38+
39+
## Benchmarks
40+
41+
The following benchmark executables are available after building the utils and framework benchmarks:
42+
43+
**Utils Benchmarks:**
44+
- `build/libs/utils/benchmark/celix_filter_benchmark`
45+
- `build/libs/utils/benchmark/celix_long_hashmap_benchmark`
46+
- `build/libs/utils/benchmark/celix_string_hashmap_benchmark`
47+
- `build/libs/utils/benchmark/celix_utils_benchmark`
48+
49+
**Framework Benchmarks:**
50+
- `build/libs/framework/benchmark/celix_framework_benchmark`
51+
52+
Paths may vary depending on your configuration and enabled options.
53+
54+
## Running Benchmarks
55+
56+
Benchmark executables are located in the `build` directory, typically under the relevant bundle or library subdirectory. To run a benchmark:
57+
58+
```sh
59+
./build/libs/utils/benchmarks/celix_utils_benchmark
60+
## Command-Line Options
61+
The benchmark executables accept standard Google Benchmark command-line options.
62+
For example, to run only benchmarks matching a specific pattern and output results in JSON format:
63+
64+
```bash
65+
./build/libs/utils/benchmark/celix_filter_benchmark --benchmark_filter=complexFilter --benchmark_format=json
66+
```
67+
68+
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:
69+
70+
```bash
71+
./build/libs/utils/benchmarks/./celix_filter_benchmark --help
72+
```
73+
74+
This will display all available Google Benchmark options.

0 commit comments

Comments
 (0)