Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,8 @@ analysis-cppcheck-build-dir
ideas

desktop.iniimages/

.cifuzz*/
.sarif/
build-vscode/
lcov.info
36 changes: 22 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(
Glob
VERSION 1.0
LANGUAGES CXX
LANGUAGES C CXX
)

find_package(cifuzz NO_SYSTEM_ENVIRONMENT_PATH)
enable_fuzz_testing()

# ---- Options ----
option(GLOB_USE_GHC_FILESYSTEM "Use ghc::filesystem instead of std::filesystem" OFF)
option(GLOB_TESTS "Run glob gtests" ON)

# ---- Include guards ----

Expand Down Expand Up @@ -93,16 +97,20 @@ packageProject(
)

# --- setup tests ---
enable_testing()

add_executable(glob_tests test/rglob_test.cpp)
set_property(TARGET glob_tests PROPERTY CXX_STANDARD 17)
target_link_libraries(glob_tests PRIVATE gtest_main ${PROJECT_NAME})
add_test(NAME glob_tests COMMAND glob_tests)

add_executable(glob_tests_single test/rglob_test.cpp)
set_property(TARGET glob_tests_single PROPERTY CXX_STANDARD 17)
target_compile_definitions(glob_tests_single PRIVATE USE_SINGLE_HEADER=1)
target_link_libraries(glob_tests_single PRIVATE gtest_main)
target_include_directories(glob_tests_single PRIVATE single_include)
add_test(NAME glob_tests_single COMMAND glob_tests_single)
if (GLOB_TESTS)
enable_testing()

add_executable(glob_tests test/rglob_test.cpp test/compile_pattern_test.cpp)
set_property(TARGET glob_tests PROPERTY CXX_STANDARD 17)
target_link_libraries(glob_tests PRIVATE gtest_main ${PROJECT_NAME})
add_test(NAME glob_tests COMMAND glob_tests)

add_executable(glob_tests_single test/rglob_test.cpp test/compile_pattern_test.cpp)
set_property(TARGET glob_tests_single PROPERTY CXX_STANDARD 17)
target_compile_definitions(glob_tests_single PRIVATE USE_SINGLE_HEADER=1)
target_link_libraries(glob_tests_single PRIVATE gtest_main)
target_include_directories(glob_tests_single PRIVATE single_include)
add_test(NAME glob_tests_single COMMAND glob_tests_single)
endif ()

add_subdirectory(cifuzz-spark)
6 changes: 6 additions & 0 deletions cifuzz-spark/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#cifuzz:build-template:begin
#add_fuzz_test({{ .FuzzTestName }} {{ .FileName }})
#target_link_libraries({{ .FuzzTestName }} PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,Glob>")
#cifuzz:build-template:end
add_fuzz_test(fuzz_compile_pattern_to_regex fuzz_compile_pattern_to_regex.cpp)
target_link_libraries(fuzz_compile_pattern_to_regex PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,Glob>")
25 changes: 25 additions & 0 deletions cifuzz-spark/fuzz_compile_pattern_to_regex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <cifuzz/cifuzz.h> // For FUZZ_TEST and FuzzedDataProvider
#include <regex> // For std::regex and std::regex_match
#include <string_view> // For std::string_view

#include "glob/glob.h" // For glob::compile_pattern_to_regex

FUZZ_TEST(const uint8_t *data, size_t size) {
if (size < 1) {
return;
}

FuzzedDataProvider fdp(data, size);
std::string glob_pattern = fdp.ConsumeRandomLengthString(50);
try {
std::regex compiled_regex = glob::compile_pattern_to_regex(glob_pattern);
// Generate fuzzed file path to match against.
std::string path = fdp.ConsumeRandomLengthString(50);
std::regex_match(path, compiled_regex);
} catch (const std::regex_error &) {
// Ignore regex errors - these are expected for invalid glob patterns.
} catch (const std::length_error &) {
// Ignore length errors - these are expected for invalid glob patterns.
}
}
74 changes: 74 additions & 0 deletions cifuzz.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
## Configuration for a CI Fuzz project
## Generated on 2025-08-25

## The build system used to build this project. If not set, cifuzz tries to
## detect the build system automatically.
## Valid values: "bazel", "cmake", "other"
build-system: cmake
## Engine used for fuzzing, default is "libfuzzer-clang".
## Valid values: "libfuzzer-clang", "honggfuzz-clang", "honggfuzz-gcc"
engine: libfuzzer-clang
## Sanitizers to use when building fuzz tests. If not set, ASan and UBSan
## are used by default.
#sanitizers:
# - address
# - undefined

## If the build system type is "other", this command is used to build the fuzz
## tests.
#build-command: make my_fuzz_test

## If the build system type is "other", this command is used to list the names
## of already existing fuzz tests in your project. This allows running all fuzz
## tests in the project without listing them explicitly, supports fuzz test
## generation and enables fuzz test completion for commands.
## The listed names should be separated by whitespace and can't include
## whitespaces themselves, i.e. 'fuzz_test1 fuzz_test_2 ...'
#list-fuzz-tests-command: echo my_fuzz_test

## Command-line arguments to pass directly to the build system to use when
## building fuzz tests.
#build-system-args:
# - -DBUILD_TESTS=ON

## Directories containing sample inputs used as seeds for running fuzz tests.
## For general information on seed corpora, see:
## https://docs.code-intelligence.com/glossary#seed-corpus
#seed-corpus-dirs:
# - path/to/seed-corpus

## Directories containing inputs for calculating coverage. These are used in
## addition to inputs found in the directory of the fuzz test.
#corpus-dirs:
# - path/to/corpus

## File containing input language keywords or other interesting byte sequences
## used for running fuzz tests.
## For libFuzzer see: https://llvm.org/docs/LibFuzzer.html#dictionaries
#dict: path/to/dictionary.dct

## Command-line arguments to pass to libFuzzer when running fuzz tests.
## See https://llvm.org/docs/LibFuzzer.html#options for possible options.
#libfuzzer-args:
# - -rss_limit_mb=4096

## Command-line arguments to pass to Honggfuzz when running fuzz tests.
## See https://github.com/google/honggfuzz/blob/master/docs/USAGE.md for possible options.
#honggfuzz-args:
# - --rlimit_rss=4096

## Maximum time to run all fuzz tests. Default is 10 minutes. The time will be
## split up evenly between multiple fuzz tests. To keep running indefinitely,
## set value to 0.
#max-fuzzing-duration: 30m

## Set to true to print output of the `cifuzz run` command as JSON.
#print-json: true

## Set to true to disable desktop notifications.
#no-notifications: true

## Set style for command output.
## Valid values: "pretty", "plain"
#style: plain
build-file: cifuzz-spark/CMakeLists.txt
2 changes: 1 addition & 1 deletion cmake/CPM.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(CPM_DOWNLOAD_VERSION 0.35.1)
set(CPM_DOWNLOAD_VERSION 0.40.8)

if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
Expand Down
2 changes: 2 additions & 0 deletions include/glob/glob.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once
#include <string>
#include <vector>
#include <regex>

#ifdef GLOB_USE_GHC_FILESYSTEM
#include <ghc/filesystem.hpp>
Expand Down Expand Up @@ -45,4 +46,5 @@ std::vector<fs::path> glob(const std::initializer_list<std::string> &pathnames);
/// Initializer list overload for convenience
std::vector<fs::path> rglob(const std::initializer_list<std::string> &pathnames);

std::regex compile_pattern_to_regex(std::string_view pattern);
} // namespace glob
4 changes: 2 additions & 2 deletions single_include/glob/glob.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ std::string translate(const std::string &pattern) {
}

static inline
std::regex compile_pattern(const std::string &pattern) {
std::regex compile_pattern_to_regex(const std::string &pattern) {
return std::regex(translate(pattern), std::regex::ECMAScript);
}

static inline
bool fnmatch(const fs::path &name, const std::string &pattern) {
return std::regex_match(name.string(), compile_pattern(pattern));
return std::regex_match(name.string(), compile_pattern_to_regex(pattern));
}

static inline
Expand Down
Loading