Switch GitHub Actions to Ubuntu 26.04 and enable control-flow coverage. Also fix compatibility issues exposed by newer GCC and Clang versions on Ubuntu 26.04: - Bump `abseil-cpp` to `20260817.0` (in `MODULE.bazel`, `MODULE.bazel.lock`, and `cmake/BuildDependencies.cmake`) to pick up the `<bmi2intrin.h>` -> `<immintrin.h>` fix in `raw_hash_set.h` needed when GCC 15 targets `x86-64-v3` (`__BMI2__`) by default. - Avoid `std::atomic<bool>` and `std::copy` in SanitizerCoverage tracing hooks (`ExecutionCoverage` and `TableOfRecentlyComparedBuffers::Insert`), using `__atomic_load_n`, `__atomic_store_n`, and `__builtin_memcpy` instead to prevent infinite recursion when unoptimized builds link instrumented COMDAT symbols with `_GLIBCXX_ASSERTIONS` enabled by default in `libstdc++` 15, and include `meta.h` directly in `table_of_recent_compares.h`. - Move `GetTypeName()` into `type_support_internal` so `PRETTY_FUNCTION` fits within GCC's 80-character `std::string_view` compile-time debug printing limit and preserves the `fuzztest::internal::` namespace prefix. - Avoid calling `std::memcpy` with a null `out.data()` pointer on empty byte vectors in `IRObject::ToCorpus`, preventing Clang from optimizing away the empty-vector branch via `memcpy`'s `nonnull` attribute. PiperOrigin-RevId: 1004136793
diff --git a/.github/workflows/bazel_test.yml b/.github/workflows/bazel_test.yml index 27bccb0..68f1086 100644 --- a/.github/workflows/bazel_test.yml +++ b/.github/workflows/bazel_test.yml
@@ -24,25 +24,28 @@ - cron: '0 8 * * *' workflow_dispatch: +permissions: + contents: read + jobs: run_unit_tests: name: Run unit tests - # TODO(xinhaoyuan): Bump to 24.04 after https://github.com/llvm/llvm-project/issues/102443 - # is fixed. - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 + permissions: + contents: read strategy: matrix: compilation_mode: ['fastbuild', 'opt', 'dbg'] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install dependencies run: | sudo apt-get update && sudo apt-get install -yq \ clang - name: Restore latest cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-cache-unit-${{ matrix.compilation_mode }} @@ -53,16 +56,16 @@ -c ${{ matrix.compilation_mode }} -- //... -//e2e_tests/... -//centipede/... - name: Save new cache based on main if: github.ref == 'refs/heads/main' - uses: actions/cache/save@v4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-cache-unit-${{ matrix.compilation_mode }}-${{ github.run_id }} run_e2e_tests: name: Run e2e tests - # TODO(xinhaoyuan): Bump to 24.04 after https://github.com/llvm/llvm-project/issues/102443 - # is fixed. - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 + permissions: + contents: read strategy: matrix: config: ['uninstrumented', 'fuzztest', 'fuzztest-experimental', 'libfuzzer'] @@ -71,7 +74,7 @@ run: | sudo sysctl -w kernel.core_pattern="" - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install dependencies run: | sudo apt-get update && sudo apt-get install -yq \ @@ -80,7 +83,7 @@ run: | EXTRA_CONFIGS=libfuzzer bazel run //bazel:setup_configs > fuzztest.bazelrc - name: Restore latest cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-cache-e2e-${{ matrix.config }} @@ -113,7 +116,7 @@ //e2e_tests:compatibility_mode_test - name: Save new cache based on main if: github.ref == 'refs/heads/main' - uses: actions/cache/save@v4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-cache-e2e-${{ matrix.config }}-${{ github.run_id }}
diff --git a/.github/workflows/bazel_test_centipede.yml b/.github/workflows/bazel_test_centipede.yml index 1bbcba0..8e31fc0 100644 --- a/.github/workflows/bazel_test_centipede.yml +++ b/.github/workflows/bazel_test_centipede.yml
@@ -24,13 +24,16 @@ - cron: '0 8 * * *' workflow_dispatch: +permissions: + contents: read + jobs: run_tests: name: Run Centipede tests - # TODO(xinhaoyuan): Bump to 24.04 after https://github.com/llvm/llvm-project/issues/102443 - # is fixed. - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 + permissions: + contents: read strategy: matrix: config: ['default', 'noriegeli', 'asan'] @@ -39,13 +42,13 @@ run: | sudo sysctl -w kernel.core_pattern="" - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install dependencies run: | sudo apt-get update && sudo apt-get install -yq \ clang llvm libssl-dev - name: Restore latest cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-centipede-cache-${{ matrix.config }} @@ -84,7 +87,7 @@ bazel test --no//fuzztest:use_riegeli --test_output=errors --linkopt=-fsanitize=address --copt=-fsanitize=address --test_env=ASAN_OPTIONS=detect_leaks=0 --platform_suffix=asan --test_timeout=600 centipede/puzzles:all - name: Save new cache based on main if: github.ref == 'refs/heads/main' - uses: actions/cache/save@v4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-centipede-cache-${{ matrix.config }}-${{ github.run_id }} @@ -92,11 +95,13 @@ name: Run Centipede tests (MacOS) runs-on: macos-15 timeout-minutes: 60 + permissions: + contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Restore latest cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-centipede-cache-mac @@ -127,7 +132,7 @@ bazel --output_user_root="${HOME}/.cache/bazel" test --test_output=errors --no//fuzztest:use_riegeli --linkopt=-fsanitize=address --copt=-fsanitize=address --test_env=ASAN_OPTIONS=detect_leaks=0 --platform_suffix=asan --test_timeout=600 centipede/puzzles:all - name: Save new cache based on main if: github.ref == 'refs/heads/main' - uses: actions/cache/save@v4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: "~/.cache/bazel" key: bazel-centipede-cache-mac-${{ github.run_id }}
diff --git a/.github/workflows/cargo_test.yml b/.github/workflows/cargo_test.yml index 4d463e2..48aa215 100644 --- a/.github/workflows/cargo_test.yml +++ b/.github/workflows/cargo_test.yml
@@ -33,7 +33,7 @@ jobs: run_cargo_tests: name: Run Cargo tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 permissions: contents: read
diff --git a/.github/workflows/cmake_test.yml b/.github/workflows/cmake_test.yml index 98b1133..8084024 100644 --- a/.github/workflows/cmake_test.yml +++ b/.github/workflows/cmake_test.yml
@@ -24,13 +24,16 @@ - cron: '0 8 * * *' workflow_dispatch: +permissions: + contents: read + jobs: run_tests: name: Run CMake tests - # TODO(xinhaoyuan): Bump to 24.04 after https://github.com/llvm/llvm-project/issues/102443 - # is fixed. - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 timeout-minutes: 60 + permissions: + contents: read env: CCACHE_BASEDIR: ${{ github.workspace }} CCACHE_DIR: ${{ github.workspace }}/.ccache @@ -42,19 +45,22 @@ run: | sudo sysctl -w kernel.core_pattern="" - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install dependencies run: | sudo apt-get update && sudo apt-get install -yq \ ccache clang gcc g++ cmake ninja-build libprotobuf-dev protobuf-compiler - name: Restore latest cache - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.CCACHE_DIR }} key: cmake-cache-${{ matrix.mode }} restore-keys: cmake-cache-${{ matrix.mode }}- - name: Check whether FuzzTest can be build using FetchContent if: matrix.mode == 'codelab' + env: + FUZZTEST_REPO: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + FUZZTEST_REPO_BRANCH: ${{ github.head_ref || github.ref_name }} run: | CC=clang CXX=clang++ cmake \ -S codelab \ @@ -63,8 +69,8 @@ -D CMAKE_C_COMPILER_LAUNCHER=ccache \ -D CMAKE_CXX_COMPILER_LAUNCHER=ccache \ -D CMAKE_BUILD_TYPE=RelWithDebug \ - -D FUZZTEST_REPO="${{ github.event.pull_request.head.repo.full_name || github.repository }}" \ - -D FUZZTEST_REPO_BRANCH="${{ github.head_ref || github.ref_name }}" \ + -D FUZZTEST_REPO="${FUZZTEST_REPO}" \ + -D FUZZTEST_REPO_BRANCH="${FUZZTEST_REPO_BRANCH}" \ && cmake --build build_codelab -j $(nproc) - name: Run all tests in default mode with clang if: matrix.mode == 'default' @@ -111,7 +117,7 @@ && ctest --test-dir build -j $(nproc) --output-on-failure -R "functional_test" - name: Save new cache based on main if: github.ref == 'refs/heads/main' - uses: actions/cache/save@v4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.CCACHE_DIR }} key: cmake-cache-${{ matrix.mode }}-${{ github.run_id }}
diff --git a/MODULE.bazel b/MODULE.bazel index 0a0dc3e..bcc9b1c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel
@@ -54,7 +54,7 @@ bazel_dep( name = "abseil-cpp", - version = "20260526.0", + version = "20260817.0", ) bazel_dep( name = "re2",
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 9454499..9d51987 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock
@@ -18,8 +18,8 @@ "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215", "https://bcr.bazel.build/modules/abseil-cpp/20250814.0/MODULE.bazel": "c43c16ca2c432566cdb78913964497259903ebe8fb7d9b57b38e9f1425b427b8", "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/MODULE.bazel": "51f2312901470cdab0dbdf3b88c40cd21c62a7ed58a3de45b365ddc5b11bcab2", - "https://bcr.bazel.build/modules/abseil-cpp/20260526.0/MODULE.bazel": "b4a76a8d70ba08aa0253fd5e374ca5a5fa6b15aba985a7bbe4467c138954830f", - "https://bcr.bazel.build/modules/abseil-cpp/20260526.0/source.json": "a39a26fec1b7037bdd7ea6c25cc098b99ae80af10ff0b6ec8c4bfe0df694f451", + "https://bcr.bazel.build/modules/abseil-cpp/20260817.0/MODULE.bazel": "026d79f94313a7b41e1d133834b802713b2d86faee4acf6008ad1dce5f0c4de3", + "https://bcr.bazel.build/modules/abseil-cpp/20260817.0/source.json": "d25e9948901242071dd567462d04fa13c40bfe27ad8b9a4bbc9cc243e84202cb", "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a", "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b", "https://bcr.bazel.build/modules/antlr4-cpp-runtime/4.13.2/MODULE.bazel": "087a9f8cb3d9643938bacb3aa97d795492dae4b23ac4cbd3ed2cdcf66a2a38da",
diff --git a/bazel/setup_configs.sh b/bazel/setup_configs.sh index 8a6524b..82f1a96 100755 --- a/bazel/setup_configs.sh +++ b/bazel/setup_configs.sh
@@ -112,9 +112,7 @@ # We apply coverage tracking instrumentation to everything but Centipede and the # FuzzTest framework itself (including GoogleTest and GoogleMock). -# TODO(b/374840534): Add -fsanitize-coverage=control-flow once we start building -# with clang 16+. -build:fuzztest-experimental --copt=-fsanitize-coverage=trace-pc-guard,pc-table,trace-loads,trace-cmp +build:fuzztest-experimental --copt=-fsanitize-coverage=trace-pc-guard,pc-table,trace-loads,trace-cmp,control-flow build:fuzztest-experimental --per_file_copt=${COMMON_FILTER},${FUZZTEST_FILTER},${CENTIPEDE_FILTER},googletest/.*,googlemock/.*@-fsanitize-coverage=0 EOF @@ -125,6 +123,13 @@ # Find llvm-config. LLVM_CONFIG=$(command -v llvm-config || + command -v llvm-config-22 || + command -v llvm-config-21 || + command -v llvm-config-20 || + command -v llvm-config-19 || + command -v llvm-config-18 || + command -v llvm-config-17 || + command -v llvm-config-16 || command -v llvm-config-15 || command -v llvm-config-14 || command -v llvm-config-13 ||
diff --git a/cmake/BuildDependencies.cmake b/cmake/BuildDependencies.cmake index fac3bd8..9aed3f0 100644 --- a/cmake/BuildDependencies.cmake +++ b/cmake/BuildDependencies.cmake
@@ -17,7 +17,7 @@ include(FetchContent) set(absl_URL https://github.com/abseil/abseil-cpp.git) -set(absl_TAG 20260526.0) +set(absl_TAG 20260817.0) set(re2_URL https://github.com/google/re2.git) set(re2_TAG 2025-11-05)
diff --git a/fuzztest/internal/BUILD b/fuzztest/internal/BUILD index 1219ada..5f393aa 100644 --- a/fuzztest/internal/BUILD +++ b/fuzztest/internal/BUILD
@@ -564,7 +564,7 @@ name = "table_of_recent_compares", hdrs = ["table_of_recent_compares.h"], deps = [ - ":type_support", + ":meta", "@abseil-cpp//absl/container:flat_hash_set", "@abseil-cpp//absl/random:bit_gen_ref", "@abseil-cpp//absl/random:distributions",
diff --git a/fuzztest/internal/CMakeLists.txt b/fuzztest/internal/CMakeLists.txt index 1ccc8a3..1b9c9e8 100644 --- a/fuzztest/internal/CMakeLists.txt +++ b/fuzztest/internal/CMakeLists.txt
@@ -546,7 +546,7 @@ HDRS "table_of_recent_compares.h" DEPS - fuzztest::type_support + fuzztest::meta absl::flat_hash_set absl::random_bit_gen_ref absl::random_distributions
diff --git a/fuzztest/internal/coverage.cc b/fuzztest/internal/coverage.cc index 20deebc..6743744 100644 --- a/fuzztest/internal/coverage.cc +++ b/fuzztest/internal/coverage.cc
@@ -101,14 +101,14 @@ max_cmp_map_[index].counter = bucketized_counter; max_cmp_map_[index].hamming = hamming_dist; max_cmp_map_[index].absolute = absolute_dist; - new_coverage_.store(true, std::memory_order_relaxed); + SetNewCoverage(true); } else if (bucketized_counter == max_cmp_map_[index].counter) { if (max_cmp_map_[index].hamming < hamming_dist) { - new_coverage_.store(true, std::memory_order_relaxed); + SetNewCoverage(true); max_cmp_map_[index].hamming = hamming_dist; } if (max_cmp_map_[index].absolute < absolute_dist) { - new_coverage_.store(true, std::memory_order_relaxed); + SetNewCoverage(true); max_cmp_map_[index].absolute = absolute_dist; } } @@ -159,7 +159,7 @@ if (this_stack > max_stack_map_[index]) { max_stack_map_[index] = this_stack; // Reaching a new max on any PC is new coverage. - new_coverage_.store(true, std::memory_order_relaxed); + SetNewCoverage(true); // Keep the total max for stats. if (this_stack > max_stack_recorded_) {
diff --git a/fuzztest/internal/coverage.h b/fuzztest/internal/coverage.h index e908da8..ce7e136 100644 --- a/fuzztest/internal/coverage.h +++ b/fuzztest/internal/coverage.h
@@ -28,7 +28,6 @@ #define FUZZTEST_FUZZTEST_INTERNAL_COVERAGE_H_ #include <algorithm> -#include <atomic> #include <cstddef> #include <cstdint> #include <cstring> @@ -87,7 +86,7 @@ void ResetState() { memset(new_cmp_counter_map_, 0, kCmpCovMapSize); memset(counter_map_.data(), 0, counter_map_.size()); - new_coverage_.store(false, std::memory_order_relaxed); + SetNewCoverage(false); max_stack_recorded_ = 0; auto& stack = test_thread_stack; @@ -129,19 +128,23 @@ void UpdateCmpMap(size_t index, uint8_t hamming_dist, uint8_t absolute_dist); bool NewCoverageFound() { - return new_coverage_.load(std::memory_order_relaxed); + return __atomic_load_n(&new_coverage_, __ATOMIC_RELAXED); + } + + void SetNewCoverage(bool new_coverage) { + __atomic_store_n(&new_coverage_, new_coverage, __ATOMIC_RELAXED); } auto& GetTablesOfRecentCompares() { return tables_of_recent_compares_; } // Flag marking if the control flow is currently in target codes. // We don't want to collect unrelated updates to cmp score and dictionary. - bool IsTracing() { return is_tracing_.load(std::memory_order_relaxed); } + bool IsTracing() { return __atomic_load_n(&is_tracing_, __ATOMIC_RELAXED); } // Right before target run, call this method with true; right after // target run, call this method with false. void SetIsTracing(bool is_tracing) { - is_tracing_.store(is_tracing, std::memory_order_relaxed); + __atomic_store_n(&is_tracing_, is_tracing, __ATOMIC_RELAXED); } // Update the PC->max stack usage map for `PC`. @@ -190,10 +193,10 @@ uint32_t max_stack_map_[kMaxStackMapSize] = {}; // Flag marking new coverage of any kind. - std::atomic<bool> new_coverage_{false}; + bool new_coverage_ = false; TablesOfRecentCompares tables_of_recent_compares_ = {}; - std::atomic<bool> is_tracing_{false}; + bool is_tracing_ = false; }; // Set the singleton ExecutionCoverage object.
diff --git a/fuzztest/internal/serialization.h b/fuzztest/internal/serialization.h index 8c3c4ce..d631158 100644 --- a/fuzztest/internal/serialization.h +++ b/fuzztest/internal/serialization.h
@@ -284,7 +284,9 @@ if (v) { T out; out.resize(v->size()); - std::memcpy(out.data(), v->data(), v->size()); + if (!v->empty()) { + std::memcpy(out.data(), v->data(), v->size()); + } return out; } }
diff --git a/fuzztest/internal/serialization_test.cc b/fuzztest/internal/serialization_test.cc index 3932ad9..1794c8b 100644 --- a/fuzztest/internal/serialization_test.cc +++ b/fuzztest/internal/serialization_test.cc
@@ -386,10 +386,13 @@ EXPECT_THAT(round_trip(E2::kEnum), Optional(E2::kEnum)); // Specializations + EXPECT_THAT(round_trip(std::vector<int8_t>{}), Optional(ElementsAre())); EXPECT_THAT(round_trip(std::vector<int8_t>{1, 2, 3}), Optional(ElementsAre(1, 2, 3))); + EXPECT_THAT(round_trip(std::vector<uint8_t>{}), Optional(ElementsAre())); EXPECT_THAT(round_trip(std::vector<uint8_t>{1, 2, 3}), Optional(ElementsAre(1, 2, 3))); + EXPECT_THAT(round_trip(std::vector<std::byte>{}), Optional(ElementsAre())); EXPECT_THAT(round_trip(std::vector<std::byte>{std::byte{1}, std::byte{2}, std::byte{3}}), Optional(ElementsAre(std::byte{1}, std::byte{2}, std::byte{3})));
diff --git a/fuzztest/internal/table_of_recent_compares.h b/fuzztest/internal/table_of_recent_compares.h index 2f61289..1b2d756 100644 --- a/fuzztest/internal/table_of_recent_compares.h +++ b/fuzztest/internal/table_of_recent_compares.h
@@ -27,7 +27,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/random/bit_gen_ref.h" #include "absl/random/distributions.h" -#include "./fuzztest/internal/type_support.h" +#include "./fuzztest/internal/meta.h" namespace fuzztest::internal { @@ -242,8 +242,8 @@ if (n >= kEntrySize) n = kEntrySize - 1; ComparedBufferEntry& entry = table_[insert_index_]; entry.buf_size = n; - std::copy(buf1, buf1 + n, entry.buf1.begin()); - std::copy(buf2, buf2 + n, entry.buf2.begin()); + __builtin_memcpy(entry.buf1.data(), buf1, n); + __builtin_memcpy(entry.buf2.data(), buf2, n); if (compact_ && ++insert_index_ == kTableSize) { compact_ = false; }
diff --git a/fuzztest/internal/type_support.h b/fuzztest/internal/type_support.h index 543b9c3..e3bef59 100644 --- a/fuzztest/internal/type_support.h +++ b/fuzztest/internal/type_support.h
@@ -102,6 +102,11 @@ return false; } +namespace type_support_internal { + +// Use a dedicated namespace so that GCC 12+'s __PRETTY_FUNCTION__ does not +// omit the `fuzztest::internal::` prefix for types defined in +// `fuzztest::internal`. template <typename T> constexpr auto GetTypeName() { absl::string_view name, prefix, suffix; @@ -113,7 +118,7 @@ prefix = "GetTypeName() [with T = "; suffix = "]"; #else - return "<TYPE>" + return "<TYPE>"; #endif // First we remove the prefix and suffix to get a fully qualified type name. ConsumePrefixUntil(name, prefix); @@ -123,6 +128,10 @@ return name; } +} // namespace type_support_internal + +using type_support_internal::GetTypeName; + template <typename T> absl::string_view GetTypeNameIfUserDefined() { using CleanT = std::remove_cv_t<std::remove_reference_t<T>>;