shrinker.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // Copyright (c) 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_FUZZ_SHRINKER_H_
  15. #define SOURCE_FUZZ_SHRINKER_H_
  16. #include <memory>
  17. #include <vector>
  18. #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
  19. #include "spirv-tools/libspirv.hpp"
  20. namespace spvtools {
  21. namespace fuzz {
  22. // Shrinks a sequence of transformations that lead to an interesting SPIR-V
  23. // binary to yield a smaller sequence of transformations that still produce an
  24. // interesting binary.
  25. class Shrinker {
  26. public:
  27. // Possible statuses that can result from running the shrinker.
  28. enum class ShrinkerResultStatus {
  29. kComplete,
  30. kFailedToCreateSpirvToolsInterface,
  31. kInitialBinaryInvalid,
  32. kInitialBinaryNotInteresting,
  33. kReplayFailed,
  34. kStepLimitReached,
  35. kAddedFunctionReductionFailed,
  36. };
  37. struct ShrinkerResult {
  38. ShrinkerResultStatus status;
  39. std::vector<uint32_t> transformed_binary;
  40. protobufs::TransformationSequence applied_transformations;
  41. };
  42. // The type for a function that will take a binary, |binary|, and return true
  43. // if and only if the binary is deemed interesting. (The function also takes
  44. // an integer argument, |counter|, that will be incremented each time the
  45. // function is called; this is for debugging purposes).
  46. //
  47. // The notion of "interesting" depends on what properties of the binary or
  48. // tools that process the binary we are trying to maintain during shrinking.
  49. using InterestingnessFunction = std::function<bool(
  50. const std::vector<uint32_t>& binary, uint32_t counter)>;
  51. Shrinker(spv_target_env target_env, MessageConsumer consumer,
  52. const std::vector<uint32_t>& binary_in,
  53. const protobufs::FactSequence& initial_facts,
  54. const protobufs::TransformationSequence& transformation_sequence_in,
  55. const InterestingnessFunction& interestingness_function,
  56. uint32_t step_limit, bool validate_during_replay,
  57. spv_validator_options validator_options);
  58. // Disables copy/move constructor/assignment operations.
  59. Shrinker(const Shrinker&) = delete;
  60. Shrinker(Shrinker&&) = delete;
  61. Shrinker& operator=(const Shrinker&) = delete;
  62. Shrinker& operator=(Shrinker&&) = delete;
  63. ~Shrinker();
  64. // Requires that when |transformation_sequence_in_| is applied to |binary_in_|
  65. // with initial facts |initial_facts_|, the resulting binary is interesting
  66. // according to |interestingness_function_|.
  67. //
  68. // If shrinking succeeded -- possibly terminating early due to reaching the
  69. // shrinker's step limit -- an associated result status is returned together
  70. // with a subsequence of |transformation_sequence_in_| that, when applied
  71. // to |binary_in_| with initial facts |initial_facts_|, produces a binary
  72. // that is also interesting according to |interestingness_function_|; this
  73. // binary is also returned.
  74. //
  75. // If shrinking failed for some reason, an appropriate result status is
  76. // returned together with an empty binary and empty transformation sequence.
  77. ShrinkerResult Run();
  78. private:
  79. // Returns the id bound for the given SPIR-V binary, which is assumed to be
  80. // valid.
  81. uint32_t GetIdBound(const std::vector<uint32_t>& binary) const;
  82. // Target environment.
  83. const spv_target_env target_env_;
  84. // Message consumer that will be invoked once for each message communicated
  85. // from the library.
  86. MessageConsumer consumer_;
  87. // The binary to which transformations are to be applied.
  88. const std::vector<uint32_t>& binary_in_;
  89. // Initial facts known to hold in advance of applying any transformations.
  90. const protobufs::FactSequence& initial_facts_;
  91. // The series of transformations to be shrunk.
  92. const protobufs::TransformationSequence& transformation_sequence_in_;
  93. // Function that decides whether a given module is interesting.
  94. const InterestingnessFunction& interestingness_function_;
  95. // Step limit to decide when to terminate shrinking early.
  96. const uint32_t step_limit_;
  97. // Determines whether to check for validity during the replaying of
  98. // transformations.
  99. const bool validate_during_replay_;
  100. // Options to control validation.
  101. spv_validator_options validator_options_;
  102. };
  103. } // namespace fuzz
  104. } // namespace spvtools
  105. #endif // SOURCE_FUZZ_SHRINKER_H_