Skip to content

Commit 69f07da

Browse files
authored
spirv-fuzz: Fix mismatch with shrinker step limit (#3985)
Fixes #3984.
1 parent 9223493 commit 69f07da

3 files changed

Lines changed: 130 additions & 8 deletions

File tree

source/fuzz/added_function_reducer.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ AddedFunctionReducer::AddedFunctionReducer(
4545
validator_options_(validator_options),
4646
shrinker_step_limit_(shrinker_step_limit),
4747
num_existing_shrink_attempts_(num_existing_shrink_attempts),
48-
num_reduction_attempts_(0) {}
48+
num_reducer_interestingness_function_invocations_(0) {}
4949

5050
AddedFunctionReducer::~AddedFunctionReducer() = default;
5151

@@ -99,16 +99,25 @@ AddedFunctionReducer::AddedFunctionReducerResult AddedFunctionReducer::Run() {
9999
protobufs::TransformationSequence transformation_sequence_out;
100100
ReplayAdaptedTransformations(reduced_binary, &binary_out,
101101
&transformation_sequence_out);
102+
// We subtract 1 from |num_reducer_interestingness_function_invocations_| to
103+
// account for the fact that spirv-reduce invokes its interestingness test
104+
// once before reduction commences in order to check that the initial module
105+
// is interesting.
106+
assert(num_reducer_interestingness_function_invocations_ > 0 &&
107+
"At a minimum spirv-reduce should have invoked its interestingness "
108+
"test once.");
102109
return {AddedFunctionReducerResultStatus::kComplete, std::move(binary_out),
103-
std::move(transformation_sequence_out), num_reduction_attempts_};
110+
std::move(transformation_sequence_out),
111+
num_reducer_interestingness_function_invocations_ - 1};
104112
}
105113

106114
bool AddedFunctionReducer::InterestingnessFunctionForReducingAddedFunction(
107115
const std::vector<uint32_t>& binary_under_reduction,
108116
const std::unordered_set<uint32_t>& irrelevant_pointee_global_variables) {
109117
uint32_t counter_for_shrinker_interestingness_function =
110-
num_existing_shrink_attempts_ + num_reduction_attempts_;
111-
num_reduction_attempts_++;
118+
num_existing_shrink_attempts_ +
119+
num_reducer_interestingness_function_invocations_;
120+
num_reducer_interestingness_function_invocations_++;
112121

113122
// The reduced version of the added function must be limited to accessing
114123
// global variables appearing in |irrelevant_pointee_global_variables|. This

source/fuzz/added_function_reducer.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,10 @@ class AddedFunctionReducer {
181181
// AddedFunctionReducer instance.
182182
const uint32_t num_existing_shrink_attempts_;
183183

184-
// Tracks the number of attempts that spirv-reduce has made in reducing the
185-
// added function.
186-
uint32_t num_reduction_attempts_;
184+
// Tracks the number of attempts that spirv-reduce has invoked its
185+
// interestingness function, which it does once at the start of reduction,
186+
// and then once more each time it makes a reduction step.
187+
uint32_t num_reducer_interestingness_function_invocations_;
187188
};
188189

189190
} // namespace fuzz

test/fuzz/shrinker_test.cpp

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ TEST(ShrinkerTest, ReduceAddedFunctions) {
144144
// compilers are kept happy. See:
145145
// https://developercommunity.visualstudio.com/content/problem/367326/problems-with-capturing-constexpr-in-lambda.html
146146
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
147-
const auto consumer = kConsoleMessageConsumer;
147+
const auto consumer = fuzzerutil::kSilentMessageConsumer;
148148

149149
SpirvTools tools(env);
150150
std::vector<uint32_t> reference_binary;
@@ -266,6 +266,118 @@ TEST(ShrinkerTest, ReduceAddedFunctions) {
266266
}
267267
}
268268

269+
TEST(ShrinkerTest, HitStepLimitWhenReducingAddedFunctions) {
270+
const std::string kReferenceModule = R"(
271+
OpCapability Shader
272+
%1 = OpExtInstImport "GLSL.std.450"
273+
OpMemoryModel Logical GLSL450
274+
OpEntryPoint Fragment %4 "main"
275+
OpExecutionMode %4 OriginUpperLeft
276+
OpSource ESSL 320
277+
%2 = OpTypeVoid
278+
%3 = OpTypeFunction %2
279+
%6 = OpTypeInt 32 1
280+
%7 = OpTypePointer Private %6
281+
%8 = OpVariable %7 Private
282+
%9 = OpConstant %6 2
283+
%10 = OpTypePointer Function %6
284+
%4 = OpFunction %2 None %3
285+
%5 = OpLabel
286+
%11 = OpVariable %10 Function
287+
OpStore %8 %9
288+
%12 = OpLoad %6 %8
289+
OpStore %11 %12
290+
OpReturn
291+
OpFunctionEnd
292+
)";
293+
294+
const std::string kDonorModule = R"(
295+
OpCapability Shader
296+
%1 = OpExtInstImport "GLSL.std.450"
297+
OpMemoryModel Logical GLSL450
298+
OpEntryPoint Fragment %4 "main"
299+
OpExecutionMode %4 OriginUpperLeft
300+
OpSource ESSL 320
301+
%2 = OpTypeVoid
302+
%3 = OpTypeFunction %2
303+
%6 = OpTypeInt 32 1
304+
%48 = OpConstant %6 3
305+
%4 = OpFunction %2 None %3
306+
%5 = OpLabel
307+
%52 = OpCopyObject %6 %48
308+
%53 = OpCopyObject %6 %52
309+
%54 = OpCopyObject %6 %53
310+
%55 = OpCopyObject %6 %54
311+
%56 = OpCopyObject %6 %55
312+
%57 = OpCopyObject %6 %56
313+
%58 = OpCopyObject %6 %48
314+
%59 = OpCopyObject %6 %58
315+
%60 = OpCopyObject %6 %59
316+
%61 = OpCopyObject %6 %60
317+
%62 = OpCopyObject %6 %61
318+
%63 = OpCopyObject %6 %62
319+
%64 = OpCopyObject %6 %48
320+
OpReturn
321+
OpFunctionEnd
322+
)";
323+
324+
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
325+
const auto consumer = fuzzerutil::kSilentMessageConsumer;
326+
327+
SpirvTools tools(env);
328+
std::vector<uint32_t> reference_binary;
329+
ASSERT_TRUE(
330+
tools.Assemble(kReferenceModule, &reference_binary, kFuzzAssembleOption));
331+
332+
spvtools::ValidatorOptions validator_options;
333+
334+
const auto variant_ir_context =
335+
BuildModule(env, consumer, kReferenceModule, kFuzzAssembleOption);
336+
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
337+
variant_ir_context.get(), validator_options, kConsoleMessageConsumer));
338+
339+
const auto donor_ir_context =
340+
BuildModule(env, consumer, kDonorModule, kFuzzAssembleOption);
341+
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
342+
donor_ir_context.get(), validator_options, kConsoleMessageConsumer));
343+
344+
PseudoRandomGenerator random_generator(0);
345+
FuzzerContext fuzzer_context(&random_generator, 100);
346+
TransformationContext transformation_context(
347+
MakeUnique<FactManager>(variant_ir_context.get()), validator_options);
348+
349+
protobufs::TransformationSequence transformations;
350+
FuzzerPassDonateModules pass(variant_ir_context.get(),
351+
&transformation_context, &fuzzer_context,
352+
&transformations, {});
353+
pass.DonateSingleModule(donor_ir_context.get(), true);
354+
355+
protobufs::FactSequence no_facts;
356+
357+
Shrinker::InterestingnessFunction interestingness_function =
358+
[consumer, env](const std::vector<uint32_t>& binary,
359+
uint32_t /*unused*/) -> bool {
360+
auto temp_ir_context =
361+
BuildModule(env, consumer, binary.data(), binary.size());
362+
uint32_t copy_object_count = 0;
363+
temp_ir_context->module()->ForEachInst(
364+
[&copy_object_count](opt::Instruction* inst) {
365+
if (inst->opcode() == SpvOpCopyObject) {
366+
copy_object_count++;
367+
}
368+
369+
});
370+
return copy_object_count >= 8;
371+
};
372+
373+
auto shrinker_result =
374+
Shrinker(env, consumer, reference_binary, no_facts, transformations,
375+
interestingness_function, 30, true, validator_options)
376+
.Run();
377+
ASSERT_EQ(Shrinker::ShrinkerResultStatus::kStepLimitReached,
378+
shrinker_result.status);
379+
}
380+
269381
} // namespace
270382
} // namespace fuzz
271383
} // namespace spvtools

0 commit comments

Comments
 (0)