// Copyright (c) 2020 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 SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_ #define SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_ #include #include namespace spvtools { namespace fuzz { // An implementation of this interface can be used to provide fresh ids on // demand when applying a transformation. // // During fuzzing this should never be required: a fuzzer pass should determine // all the fresh ids it requires to apply a transformation. // // However, during shrinking we can have the situation where, after removing // an early transformation, a later transformation needs more ids. // // As an example, suppose a SPIR-V function originally has this form: // // main() { // stmt1; // stmt2; // stmt3; // stmt4; // } // // Now suppose two *outlining* transformations are applied. The first // transformation, T1, outlines "stmt1; stmt2;" into a function foo, giving us: // // foo() { // stmt1; // stmt2; // } // // main() { // foo(); // stmt3; // stmt4; // } // // The second transformation, T2, outlines "foo(); stmt3;" from main into a // function bar, giving us: // // foo() { // stmt1; // stmt2; // } // // bar() { // foo(); // stmt3; // } // // main() { // bar(); // stmt4; // } // // Suppose that T2 used a set of fresh ids, FRESH, in order to perform its // outlining. // // Now suppose that during shrinking we remove T1, but still want to apply T2. // The fresh ids used by T2 - FRESH - are sufficient to outline "foo(); stmt3;". // However, because we did not apply T1, "foo();" does not exist and instead the // task of T2 is to outline "stmt1; stmt2; stmt3;". The set FRESH contains // *some* of the fresh ids required to do this (those for "stmt3;"), but not all // of them (those for "stmt1; stmt2;" are missing). // // A source of overflow ids can be used to allow the shrinker to proceed // nevertheless. // // It is desirable to use overflow ids only when needed. In our worked example, // T2 should still use the ids from FRESH when handling "stmt3;", because later // transformations might refer to those ids and will become inapplicable if // overflow ids are used instead. class OverflowIdSource { public: virtual ~OverflowIdSource(); // Returns true if and only if this source is capable of providing overflow // ids. virtual bool HasOverflowIds() const = 0; // Precondition: HasOverflowIds() must hold. Returns the next available // overflow id. virtual uint32_t GetNextOverflowId() = 0; // Returns the set of overflow ids from this source that have been previously // issued via calls to GetNextOverflowId(). virtual const std::unordered_set& GetIssuedOverflowIds() const = 0; }; } // namespace fuzz } // namespace spvtools #endif // SOURCE_FUZZ_OVERFLOW_ID_SOURCE_H_