diff --git a/libcxx/test/libcxx/selftest/fuzz.cpp/compile-error.fuzz.cpp b/libcxx/test/libcxx/selftest/fuzz.cpp/compile-error.fuzz.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/selftest/fuzz.cpp/compile-error.fuzz.cpp @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// XFAIL: * + +// Make sure the test DOES NOT pass if it fails at compile-time + +#include +#include + +struct Foo {}; +typedef Foo::x x; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t) { return 0; } diff --git a/libcxx/test/libcxx/selftest/fuzz.cpp/link-error.fuzz.cpp b/libcxx/test/libcxx/selftest/fuzz.cpp/link-error.fuzz.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/selftest/fuzz.cpp/link-error.fuzz.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// XFAIL: * + +// Make sure the test DOES NOT pass if it fails at link-time + +#include +#include + +extern void this_is_an_undefined_symbol(); + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t) { + this_is_an_undefined_symbol(); + + return 0; +} diff --git a/libcxx/test/libcxx/selftest/fuzz.cpp/run-error.fuzz.cpp b/libcxx/test/libcxx/selftest/fuzz.cpp/run-error.fuzz.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/selftest/fuzz.cpp/run-error.fuzz.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// XFAIL: * + +// RUN_FLAGS: -runs=1 + +// Make sure the test DOES NOT pass if it fails at runtime. + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t) { + volatile int* ptr = nullptr; + volatile int val = *ptr; + (void)val; + + return 0; +} diff --git a/libcxx/test/libcxx/selftest/fuzz.cpp/run-success.fuzz.cpp b/libcxx/test/libcxx/selftest/fuzz.cpp/run-success.fuzz.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/selftest/fuzz.cpp/run-success.fuzz.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Make sure the test passes pass if it succeeds at runtime. + +#include +#include + +// RUN_FLAGS: -runs=1 + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t) { return 0; } diff --git a/libcxx/test/libcxx/fuzzing/unique.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/unique.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/unique.pass.cpp rename to libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/unique.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/unique.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/unique.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { std::vector working(data, data + size); diff --git a/libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/unique_copy.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp rename to libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/unique_copy.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/unique_copy.fuzz.cpp @@ -8,13 +8,15 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { std::vector working(data, data + size); diff --git a/libcxx/test/libcxx/fuzzing/search.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.search/search.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/search.pass.cpp rename to libcxx/test/std/algorithms/alg.nonmodifying/alg.search/search.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/search.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.search/search.fuzz.cpp @@ -8,13 +8,15 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { if (size < 2) diff --git a/libcxx/test/libcxx/fuzzing/make_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/make_heap.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/make_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { std::vector working(data, data + size); diff --git a/libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/pop_heap.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/pop_heap.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/pop_heap.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { if (size < 2) diff --git a/libcxx/test/libcxx/fuzzing/push_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/push_heap.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/push_heap.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/push_heap.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/push_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/push_heap.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { if (size < 2) diff --git a/libcxx/test/libcxx/fuzzing/nth_element.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.nth.element/nth_element.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/nth_element.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.nth.element/nth_element.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/nth_element.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.nth.element/nth_element.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" // Use the first element as a position into the data extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { diff --git a/libcxx/test/libcxx/fuzzing/partition.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.partitions/partition.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/partition.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.partitions/partition.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/partition.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.partitions/partition.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { auto is_even = [](auto x) { return x % 2 == 0; }; diff --git a/libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.partitions/partition_copy.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.partitions/partition_copy.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.partitions/partition_copy.fuzz.cpp @@ -8,13 +8,15 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { auto is_even = [](auto t) { diff --git a/libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.partitions/stable_partition.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.partitions/stable_partition.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.partitions/stable_partition.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { auto is_even = [](auto b) { return b.key % 2 == 0; }; diff --git a/libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/partial_sort_copy.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/partial_sort_copy.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort.copy/partial_sort_copy.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" // Use the first element as a count extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { diff --git a/libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/partial_sort.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/partial_sort.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/partial_sort.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" // Use the first element as a position into the data extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { diff --git a/libcxx/test/libcxx/fuzzing/sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/sort.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { std::vector working(data, data + size); diff --git a/libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp rename to libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.fuzz.cpp @@ -8,12 +8,14 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { std::vector input; diff --git a/libcxx/test/libcxx/fuzzing/random.pass.cpp b/libcxx/test/std/numerics/rand/rand.dist/random.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/random.pass.cpp rename to libcxx/test/std/numerics/rand/rand.dist/random.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/random.pass.cpp +++ b/libcxx/test/std/numerics/rand/rand.dist/random.fuzz.cpp @@ -8,6 +8,8 @@ // UNSUPPORTED: c++03, c++11 +// RUN_FLAGS: -max_total_time=10 + #include #include #include @@ -17,7 +19,7 @@ #include #include -#include "fuzz.h" +#include "fuzz_helper.h" template std::vector GetValues(const std::uint8_t *data, std::size_t size) { diff --git a/libcxx/test/libcxx/fuzzing/regex.pass.cpp b/libcxx/test/std/re/regex.fuzz.cpp rename from libcxx/test/libcxx/fuzzing/regex.pass.cpp rename to libcxx/test/std/re/regex.fuzz.cpp --- a/libcxx/test/libcxx/fuzzing/regex.pass.cpp +++ b/libcxx/test/std/re/regex.fuzz.cpp @@ -10,12 +10,14 @@ // UNSUPPORTED: no-exceptions // UNSUPPORTED: no-localization +// RUN_FLAGS: -max_total_time=1 + #include #include #include #include -#include "fuzz.h" +#include "fuzz_helper.h" template static int regex_test(const std::uint8_t *data, std::size_t size) { diff --git a/libcxx/test/libcxx/fuzzing/fuzz.h b/libcxx/test/support/fuzz_helper.h rename from libcxx/test/libcxx/fuzzing/fuzz.h rename to libcxx/test/support/fuzz_helper.h --- a/libcxx/test/libcxx/fuzzing/fuzz.h +++ b/libcxx/test/support/fuzz_helper.h @@ -109,37 +109,4 @@ return true; } -// When running inside OSS-Fuzz, we link against a fuzzing library that defines -// main() and calls LLVMFuzzerTestOneInput. -// -// Otherwise, when e.g. running the Lit tests, we define main() to run fuzzing -// tests on a few inputs. -#if !defined(LIBCPP_OSS_FUZZ) -extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t); - -int main(int, char**) { - const char* test_cases[] = { - "", - "s", - "bac", - "bacasf", - "lkajseravea", - "adsfkajdsfjkas;lnc441324513,34535r34525234", - "b*c", - "ba?sf", - "lka*ea", - "adsf*kas;lnc441[0-9]1r34525234" - }; - - for (const char* tc : test_cases) { - const std::size_t size = std::strlen(tc); - const std::uint8_t* data = reinterpret_cast(tc); - int result = LLVMFuzzerTestOneInput(data, size); - assert(result == 0); - } - - return 0; -} -#endif // !LIBCPP_OSS_FUZZ - #endif // TEST_LIBCXX_FUZZING_FUZZ_H diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot --- a/libcxx/utils/ci/run-buildbot +++ b/libcxx/utils/ci/run-buildbot @@ -347,18 +347,19 @@ echo "--- Generating CMake" ${CMAKE} \ - -S "${MONOREPO_ROOT}/llvm" \ - -B "${BUILD_DIR}" \ - -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ - -DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ - -DLLVM_ENABLE_PROJECTS="clang" \ - -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ - -DLLVM_RUNTIME_TARGETS="$(${CXX} --print-target-triple)" \ - -DLLVM_TARGETS_TO_BUILD="host" \ - -DRUNTIMES_BUILD_ALLOW_DARWIN=ON \ - -DLLVM_ENABLE_ASSERTIONS=ON + -S "${MONOREPO_ROOT}/llvm" \ + -B "${BUILD_DIR}" \ + -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ + -DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DLLVM_ENABLE_PROJECTS="clang" \ + -DLLVM_ENABLE_RUNTIMES="compiler-rt;libcxx;libcxxabi;libunwind" \ + -DLLVM_RUNTIME_TARGETS="$(${CXX} --print-target-triple)" \ + -DLLVM_TARGETS_TO_BUILD="host" \ + -DCOMPILER_RT_CXX_LIBRARY=libcxx \ + -DRUNTIMES_BUILD_ALLOW_DARWIN=ON \ echo "+++ Running the libc++ and libc++abi tests" ${NINJA} -C "${BUILD_DIR}" check-runtimes diff --git a/libcxx/utils/libcxx/test/dsl.py b/libcxx/utils/libcxx/test/dsl.py --- a/libcxx/utils/libcxx/test/dsl.py +++ b/libcxx/utils/libcxx/test/dsl.py @@ -148,9 +148,9 @@ @_memoizeExpensiveOperation( - lambda c, p, args=None: (c.substitutions, c.environment, p, args) + lambda c, p, args=None, additional_build_args=None: (c.substitutions, c.environment, p, args, additional_build_args) ) -def programOutput(config, program, args=None): +def programOutput(config, program, args=None, additional_build_args=None): """ Compiles a program for the test target, run it on the test target and return the output. @@ -161,10 +161,14 @@ """ if args is None: args = [] + + if additional_build_args is None: + additional_build_args = [] + with _makeConfigTest(config) as test: with open(test.getSourcePath(), "w") as source: source.write(program) - _, err, exitCode, _, buildcmd = _executeWithFakeConfig(test, ["%{build}"]) + _, err, exitCode, _, buildcmd = _executeWithFakeConfig(test, ["%{{build}} {}".format(" ".join(additional_build_args))]) if exitCode != 0: raise ConfigurationCompilationError( "Failed to build program, cmd:\n{}\nstderr is:\n{}".format( @@ -184,9 +188,9 @@ @_memoizeExpensiveOperation( - lambda c, p, args=None: (c.substitutions, c.environment, p, args) + lambda c, p, args=None, additional_build_args=None: (c.substitutions, c.environment, p, args, additional_build_args) ) -def programSucceeds(config, program, args=None): +def programSucceeds(config, program, args=None, additional_build_args=None): """ Compiles a program for the test target, run it on the test target and return whether it completed successfully. @@ -196,9 +200,11 @@ %{exec} does. """ try: - programOutput(config, program, args) + programOutput(config, program, args, additional_build_args) except ConfigurationRuntimeError: return False + except ConfigurationCompilationError: + return False return True diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -98,6 +98,17 @@ name="verify-support", when=lambda cfg: hasCompileFlag(cfg, "-Xclang -verify-ignore-unexpected"), ), + Feature( + name="fuzzer-support", + when=lambda cfg: programSucceeds(cfg, """ + #include + #include + + extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *, std::size_t) { + return 0; + } + """, ["-runs=1"], ["-fsanitize=fuzzer"]) + ), Feature( name="non-lockfree-atomics", when=lambda cfg: sourceBuilds( diff --git a/libcxx/utils/libcxx/test/format.py b/libcxx/utils/libcxx/test/format.py --- a/libcxx/utils/libcxx/test/format.py +++ b/libcxx/utils/libcxx/test/format.py @@ -121,11 +121,13 @@ substitutions.append( ("%{build}", "%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe") ) - substitutions.append(("%{run}", "%{exec} %t.exe")) + substitutions.append(("%{run_flags}", "")) + substitutions.append(("%{run}", "%{exec} %t.exe %{run_flags}")) # Parse the test file, including custom directives additionalCompileFlags = [] fileDependencies = [] + runFlags = [] parsers = [ lit.TestRunner.IntegratedTestKeywordParser( "FILE_DEPENDENCIES:", @@ -137,6 +139,11 @@ lit.TestRunner.ParserKind.LIST, initial_value=additionalCompileFlags, ), + lit.TestRunner.IntegratedTestKeywordParser( + "RUN_FLAGS:", + lit.TestRunner.ParserKind.LIST, + initial_value=runFlags, + ), ] # Add conditional parsers for ADDITIONAL_COMPILE_FLAGS. This should be replaced by first @@ -170,7 +177,8 @@ substitutions = [ (s, x + " " + " ".join(additionalCompileFlags)) if s == "%{compile_flags}" - else (s, x) + else (s, x + " " + " ".join(runFlags)) + if (s == "%{run_flags}") else (s, x) for (s, x) in substitutions ] @@ -218,6 +226,10 @@ automatically marked as UNSUPPORTED if the compiler does not support Clang-verify. + FOO.fuzz.cpp - Compiles with -fsanitize=fuzzer -O3. This is disabled + if the compiler doesn't support libfuzzer or libfuzzer + is built with a different standard library. + Substitution requirements =============================== @@ -287,6 +299,7 @@ "[.]gen[.][^.]+$", "[.]verify[.]cpp$", "[.]fail[.]cpp$", + "[.]fuzz[.]cpp$", ] sourcePath = testSuite.getSourcePath(pathInSuite) @@ -310,6 +323,7 @@ "-Xclang -verify -Xclang -verify-ignore-unexpected=note -ferror-limit=0" ) supportsVerify = "verify-support" in test.config.available_features + supportsFuzzer = "fuzzer-support" in test.config.available_features filename = test.path_in_suite[-1] if re.search("[.]sh[.][^.]+$", filename): @@ -359,7 +373,17 @@ elif filename.endswith(".pass.cpp") or filename.endswith(".pass.mm"): steps = [ "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe", - "%dbg(EXECUTED AS) %{exec} %t.exe", + "%dbg(EXECUTED AS) %{exec} %t.exe %{run_flags}", + ] + return self._executeShTest(test, litConfig, steps) + elif filename.endswith(".fuzz.cpp"): + if not supportsFuzzer: + return lit.Test.Result( + lit.Test.UNSUPPORTED, + "Test {} requires support for libFuzzer, which isn't supported by the compiler".format(test.getFullName())) + steps = [ + "%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -fsanitize=fuzzer -O3 -o %t.exe", + "%dbg(EXECUTED AS) %{exec} %t.exe %{run_flags}", ] return self._executeShTest(test, litConfig, steps) else: