Skip to content

Commit

Permalink
feat: add fuzzing harnesses (#925)
Browse files Browse the repository at this point in the history
  • Loading branch information
cktii authored Feb 25, 2025
1 parent 1b9e0e2 commit 14589e5
Show file tree
Hide file tree
Showing 20 changed files with 780 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ CMakeSettings.json
.pixi

CMakeUserPresets.json

tags
78 changes: 54 additions & 24 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,9 @@ cmake_minimum_required(VERSION 3.16.3) # version on Ubuntu Focal

project(behaviortree_cpp VERSION 4.6.2 LANGUAGES C CXX)

set(CMAKE_CONFIG_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CONFIG_PATH}")

set(BTCPP_LIBRARY ${PROJECT_NAME})

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN)
else()
add_definitions(-Wpedantic -fno-omit-frame-pointer)
endif()

# create compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)


#---- project configuration ----
option(BTCPP_SHARED_LIBS "Build shared libraries" ON)
option(BTCPP_BUILD_TOOLS "Build commandline tools" ON)
Expand All @@ -35,6 +14,48 @@ option(BTCPP_GROOT_INTERFACE "Add Groot2 connection. Requires ZeroMQ" ON)
option(BTCPP_SQLITE_LOGGING "Add SQLite logging." ON)

option(USE_V3_COMPATIBLE_NAMES "Use some alias to compile more easily old 3.x code" OFF)
option(ENABLE_FUZZING "Enable fuzzing builds" OFF)
option(USE_AFLPLUSPLUS "Use AFL++ instead of libFuzzer" OFF)
option(ENABLE_DEBUG "Enable debug build with full symbols" OFF)
option(FORCE_STATIC_LINKING "Force static linking of all dependencies" OFF)

set(BASE_FLAGS "")

if(ENABLE_DEBUG)
list(APPEND BASE_FLAGS
-g3
-ggdb3
-O0
-fno-omit-frame-pointer
)
endif()

# Include fuzzing configuration if enabled
if(ENABLE_FUZZING)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/fuzzing_build.cmake)
else()
# Apply base flags for non-fuzzing builds
add_compile_options(${BASE_FLAGS})
add_link_options(${BASE_FLAGS})
endif()

set(CMAKE_CONFIG_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CONFIG_PATH}")

set(BTCPP_LIBRARY ${PROJECT_NAME})

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN)
else()
add_definitions(-Wpedantic -fno-omit-frame-pointer)
endif()

if(USE_V3_COMPATIBLE_NAMES)
add_definitions(-DUSE_BTCPP3_OLD_NAMES)
Expand Down Expand Up @@ -189,20 +210,29 @@ target_compile_definitions(${BTCPP_LIBRARY} PUBLIC BTCPP_LIBRARY_VERSION="${CMAK
target_compile_features(${BTCPP_LIBRARY} PUBLIC cxx_std_17)

if(MSVC)
target_compile_options(${BTCPP_LIBRARY} PRIVATE "/source-charset:utf-8")
target_compile_options(${BTCPP_LIBRARY} PRIVATE "/source-charset:utf-8")
else()
target_compile_options(${BTCPP_LIBRARY} PRIVATE -Wall -Wextra)
if(ENABLE_DEBUG)
target_compile_options(${BTCPP_LIBRARY} PRIVATE -Wall -Wextra -g3 -ggdb3 -O0 -fno-omit-frame-pointer)
else()
target_compile_options(${BTCPP_LIBRARY} PRIVATE -Wall -Wextra)
endif()
endif()

add_library(BT::${BTCPP_LIBRARY} ALIAS ${BTCPP_LIBRARY})

# Add fuzzing targets
if(ENABLE_FUZZING)
add_fuzzing_targets()
endif()

#############################################################
message( STATUS "BTCPP_LIB_DESTINATION: ${BTCPP_LIB_DESTINATION} " )
message( STATUS "BTCPP_INCLUDE_DESTINATION: ${BTCPP_INCLUDE_DESTINATION} " )
message( STATUS "BTCPP_UNIT_TESTS: ${BTCPP_UNIT_TESTS} " )

if (BTCPP_UNIT_TESTS OR BTCPP_EXAMPLES)
add_subdirectory(sample_nodes)
add_subdirectory(sample_nodes)
endif()

######################################################
Expand Down
153 changes: 153 additions & 0 deletions cmake/fuzzing_build.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Fuzzing configuration
# Supports both local fuzzing and OSS-Fuzz integration

# Detect if we're running in OSS-Fuzz environment
if(DEFINED ENV{LIB_FUZZING_ENGINE})
set(OSS_FUZZ ON)
message(STATUS "OSS-Fuzz environment detected")
else()
set(OSS_FUZZ OFF)
endif()

# Auto-detect AFL++ compiler if not in OSS-Fuzz mode
if(NOT OSS_FUZZ AND (CMAKE_C_COMPILER MATCHES ".*afl-.*" OR CMAKE_CXX_COMPILER MATCHES ".*afl-.*"))
set(USE_AFLPLUSPLUS ON CACHE BOOL "Use AFL++ instead of libFuzzer" FORCE)
message(STATUS "AFL++ compiler detected - automatically enabling AFL++ mode")
endif()

# When building for fuzzing, we want static library by default
set(BTCPP_SHARED_LIBS OFF CACHE BOOL "Build static library for fuzzing" FORCE)

# Only apply static linking settings if explicitly requested
if(FORCE_STATIC_LINKING)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(BUILD_SHARED_LIBS OFF)

# Force static linking for dependencies
if(BTCPP_GROOT_INTERFACE)
set(ZeroMQ_USE_STATIC_LIBS ON)
set(ZEROMQ_STATIC_LIBRARY ON)
endif()

if(BTCPP_SQLITE_LOGGING)
set(SQLite3_USE_STATIC_LIBS ON)
endif()
endif()

# Set up flags for local fuzzing (not used for OSS-Fuzz)
if(NOT OSS_FUZZ)
list(APPEND BASE_FLAGS -O2)

if(USE_AFLPLUSPLUS)
set(SANITIZER_FLAGS
-fsanitize=address,undefined
)
else()
# For libFuzzer, use fuzzer-no-link for the library
set(SANITIZER_FLAGS
-fsanitize=address,undefined,fuzzer-no-link
)
endif()

# Apply sanitizer flags to the base library
list(APPEND BASE_FLAGS ${SANITIZER_FLAGS})

add_compile_options(${BASE_FLAGS})
add_link_options(${BASE_FLAGS})
endif()

# Disable certain features during fuzzing
set(BTCPP_EXAMPLES OFF CACHE BOOL "Disable examples during fuzzing" FORCE)
set(BTCPP_BUILD_TOOLS OFF CACHE BOOL "Disable tools during fuzzing" FORCE)
set(BTCPP_UNIT_TESTS OFF CACHE BOOL "Disable tests during fuzzing" FORCE)
set(BTCPP_SHARED_LIBS OFF CACHE BOOL "Build static library for fuzzing" FORCE)

# Function to apply fuzzing flags for local development builds
function(apply_local_fuzzing_flags target)
target_compile_options(${target} PRIVATE
${BASE_FLAGS}
${SANITIZER_FLAGS}
)

if(FORCE_STATIC_LINKING)
if(USE_AFLPLUSPLUS)
target_link_options(${target} PRIVATE
${BASE_FLAGS}
${SANITIZER_FLAGS}
-static-libstdc++
-static-libgcc
-fsanitize=fuzzer
)
else()
target_link_options(${target} PRIVATE
${BASE_FLAGS}
-fsanitize=fuzzer
${SANITIZER_FLAGS}
-static-libstdc++
-static-libgcc
)
endif()
else()
if(USE_AFLPLUSPLUS)
target_link_options(${target} PRIVATE
${BASE_FLAGS}
${SANITIZER_FLAGS}
-fsanitize=fuzzer
)
else()
target_link_options(${target} PRIVATE
${BASE_FLAGS}
-fsanitize=fuzzer
${SANITIZER_FLAGS}
)
endif()
endif()
endfunction()

# Function to add fuzzing targets - compatible with both local and OSS-Fuzz builds
function(add_fuzzing_targets)
set(FUZZERS bt_fuzzer script_fuzzer bb_fuzzer)

foreach(fuzzer ${FUZZERS})
add_executable(${fuzzer} fuzzing/${fuzzer}.cpp)

if(OSS_FUZZ)
# For OSS-Fuzz environment, we rely on environment variables
# like $CC, $CXX, $CFLAGS, $CXXFLAGS, and $LIB_FUZZING_ENGINE
target_link_libraries(${fuzzer} PRIVATE
${BTCPP_LIBRARY}
${BTCPP_EXTRA_LIBRARIES}
$ENV{LIB_FUZZING_ENGINE}
)
else()
# For local development, use our own flags
apply_local_fuzzing_flags(${fuzzer})
target_link_libraries(${fuzzer} PRIVATE
${BTCPP_LIBRARY}
${BTCPP_EXTRA_LIBRARIES}
)
endif()

# Setup corpus directories (useful for both environments)
set(CORPUS_DIR ${CMAKE_BINARY_DIR}/corpus/${fuzzer})
file(MAKE_DIRECTORY ${CORPUS_DIR})
endforeach()

# Copy corpus files if they exist (useful for local testing)
# OSS-Fuzz provides its own corpus handling
if(NOT OSS_FUZZ)
file(GLOB BT_CORPUS_FILES "${CMAKE_SOURCE_DIR}/fuzzing/corpus/bt_corpus/*")
file(GLOB SCRIPT_CORPUS_FILES "${CMAKE_SOURCE_DIR}/fuzzing/corpus/script_corpus/*")
file(GLOB BB_CORPUS_FILES "${CMAKE_SOURCE_DIR}/fuzzing/corpus/bb_corpus/*")

if(BT_CORPUS_FILES)
file(COPY ${BT_CORPUS_FILES} DESTINATION ${CMAKE_BINARY_DIR}/corpus/bt_fuzzer)
endif()
if(SCRIPT_CORPUS_FILES)
file(COPY ${SCRIPT_CORPUS_FILES} DESTINATION ${CMAKE_BINARY_DIR}/corpus/script_fuzzer)
endif()
if(BB_CORPUS_FILES)
file(COPY ${BB_CORPUS_FILES} DESTINATION ${CMAKE_BINARY_DIR}/corpus/bb_fuzzer)
endif()
endif()
endfunction()
21 changes: 21 additions & 0 deletions fuzzing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Fuzzing BehaviorTree.CPP

You can build the existing harnesses either for libfuzzer or AFL++.
Building the fuzzers requires `clang` (libfuzzer) or an installed version
of [AFL++](https://github.com/AFLplusplus/AFLplusplus).

## libfuzzer

```bash
mkdir build_libfuzzer && cd build_libfuzzer
cmake -DENABLE_FUZZING=ON ..
```

## AFL++

```bash
export CC=afl-clang-fast
export CXX=afl-clang-fast++
mkdir build_afl && cd build_afl
cmake -DENABLE_FUZZING=ON -DUSE_AFLPLUSPLUS=ON ..
```
Loading

0 comments on commit 14589e5

Please sign in to comment.