// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_ #define FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_ #include <functional> #include <iostream> #include <memory> #include <optional> #include <string> #include <string_view> #include <tuple> #include <type_traits> #include <utility> #include <vector> #include "absl/status/status.h" #include "absl/strings/str_format.h" #include "absl/types/span.h" #include "./fuzztest/internal/any.h" #include "./fuzztest/internal/domains/domain.h" #include "./fuzztest/internal/logging.h" #include "./fuzztest/internal/meta.h" #include "./fuzztest/internal/printer.h" #include "./fuzztest/internal/registration.h" #include "./fuzztest/internal/type_support.h" namespace fuzztest::internal { // The interface for test fixtures with setup and teardown methods that need to // be explicitly called by the testing framework. class FixtureWithExplicitSetUp { … }; // Marker interfaces for specifying the fixture's instantiation semantics: // // - Per-iteration semantics: The fixture object is instantiated and discarded // once per fuzz test iteration. // // - Per-fuzz-test semantics: The fixture object is instantiated and discarded // once per fuzz test. The same object is reused in all fuzz test // iterations. class PerIterationFixture : public FixtureWithExplicitSetUp { … }; class PerFuzzTestFixture : public FixtureWithExplicitSetUp { … }; class UntypedFixtureDriver { … }; // Typed subinterface with functionality that depends on knowing `ValueType`. // `SeedProvider` is the type of the function returning dynamically initialized // seeds. template <typename ValueType, typename SeedProvider> class TypedFixtureDriver : public UntypedFixtureDriver { … }; // ForceVectorForStringView is a temporary hack for reliably // finding buffer overflows. ASAN cannot detect small overflows in // std::string-s. See related bug at // https://bugs.llvm.org/show_bug.cgi?id=26380. As a temporary // workaround, we enable finding overflows by copying the contents // of the original string into a separate temporary heap buffer. // TODO(b/194687521): Remove this when we (or ASAN) detect overflows // in strings. struct ForceVector { … }; template <typename Dest, typename Src> decltype(auto) ForceVectorForStringView(Src&& src) { … } // The base class for fixture drivers. // // A fixture driver is used for maintaining a fixture -- constructing it, // setting it up, tearing it down, and destructing it -- during a fuzz test. It // also acts as a proxy to the fixture's target function. // // The type parameters are: // - `DomainT` -- the type of the domain. Eg `Domain<std::tuple<int>>`. // - `Fixture` -- the type of the test fixture. // - `TargetFunction` -- the type of the fixture's target function. // - `SeedProvider` -- the type of the function returning dynamically // initialized seeds. template <typename DomainT, typename Fixture, typename TargetFunction, typename SeedProvider> class FixtureDriver; // Specialization for `TargetFunction = void(BaseFixture::*)(Args...)` // // The new type parameters are: // - `BaseFixture` -- the class from which `Fixture` is derived and which has // the target function. // - `Args...` -- the types of the target function's parameters. FixtureDriver<DomainT, Fixture, void (BaseFixture::*)(Args...), SeedProvider>; // Specialization for `Fixture = NoFixture`. // This is used for FUZZ_TEST invocations that do not require a fixture. // TargetFunction must be `void(*)(Args...)` // // The new type parameters are: // - `Args...` -- the types of the target function's parameters. FixtureDriver<DomainT, NoFixture, void (*)(Args...), SeedProvider>; template <typename DomainT, typename Fixture, typename TargetFunction, typename SeedProvider, typename = void> class FixtureDriverImpl; // The fixture driver for "NoFixture", which is the tag used for the FUZZ_TEST // macro that uses no fixtures. No fixture is created. FixtureDriverImpl<DomainT, NoFixture, TargetFunction, SeedProvider>; // The fixture driver for default-constructible classes that act like fixtures: // their setup is in the constructor, teardown is in the destructor, and they // have a target function. Such fixtures are instantiated and destructed once // per fuzz test. FixtureDriverImpl<DomainT, Fixture, TargetFunction, SeedProvider, std::enable_if_t<std::conjunction_v<std::is_default_constructible<Fixture>, std::negation<std::is_base_of<FixtureWithExplicitSetUp, Fixture>>>>>; // The fixture driver for test fixtures with explicit setup that assume the // "per-iteration" semantics. FixtureDriverImpl<DomainT, Fixture, void (BaseFixture::*)(Args...), SeedProvider, std::enable_if_t<std::conjunction_v<std::is_default_constructible<Fixture>, std::is_base_of<BaseFixture, Fixture>, std::is_base_of<PerIterationFixture, Fixture>>>>; // The fixture driver for test fixtures with explicit setup that assume the // "per-fuzz-test" semantics. FixtureDriverImpl<DomainT, Fixture, void (BaseFixture::*)(Args...), SeedProvider, std::enable_if_t<std::conjunction_v<std::is_default_constructible<Fixture>, std::is_base_of<BaseFixture, Fixture>, std::is_base_of<PerFuzzTestFixture, Fixture>>>>; } // namespace fuzztest::internal #endif // FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_