diff options
author | alan-baker <alanbaker@google.com> | 2022-12-06 11:22:33 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-06 11:22:33 -0500 |
commit | 9c6a925c87d4c6e203e440ecc8a57018e5bb8c4b (patch) | |
tree | 834cdf10853a11cdf13152d2934817fdc9c13922 | |
parent | 7b8f00f00a5b18374a294f728ec87565c2fc4ca1 (diff) | |
download | spirv-tools-9c6a925c87d4c6e203e440ecc8a57018e5bb8c4b.tar.gz |
Fix infinite loop in validator (#5006)
Fixes https://crbug.com/oss-fuzz/53510
* Fix infinite loop that could occur in structured cfg validation due to
an invalid cfg
-rw-r--r-- | source/val/construct.cpp | 4 | ||||
-rw-r--r-- | source/val/validate_cfg.cpp | 1 | ||||
-rw-r--r-- | test/val/val_cfg_test.cpp | 44 |
3 files changed, 48 insertions, 1 deletions
diff --git a/source/val/construct.cpp b/source/val/construct.cpp index 1b6a54f8..1ca81d41 100644 --- a/source/val/construct.cpp +++ b/source/val/construct.cpp @@ -167,7 +167,9 @@ bool Construct::IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const { if ((use.first->opcode() == spv::Op::OpLoopMerge || use.first->opcode() == spv::Op::OpSelectionMerge) && use.second == 1 && - use.first->block()->structurally_dominates(*block)) { + use.first->block()->structurally_dominates(*block) && + // A header likely declared itself as its merge. + use.first->block() != block) { return use.first->block(); } } diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index 06e4d671..24d24169 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -752,6 +752,7 @@ spv_result_t StructuredControlFlowChecks( _.getIdName(merge->id()), "does not structurally dominate"); } + // If it's really a merge block for a selection or loop, then it must be // *strictly* structrually dominated by the header. if (construct.ExitBlockIsMergeBlock() && (header == merge)) { diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index d2edec1d..561e817e 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -4630,6 +4630,50 @@ OpFunctionEnd "blocks but the standard requires exactly one")); } +TEST_F(ValidateCFG, BadSwitch) { + const std::string text = R"( + OpCapability StorageImageExtendedFormats + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "blah" %58 + OpExecutionMode %2 OriginUpperLeft + OpName %BAD "BAD" + %11 = OpTypeVoid + %12 = OpTypeFunction %11 + %19 = OpTypeInt 32 1 + %21 = OpConstant %19 555758549 + %2 = OpFunction %11 None %12 + %4 = OpLabel + OpBranch %33 + %33 = OpLabel + OpLoopMerge %34 %35 None + OpBranch %55 + %BAD = OpLabel + OpSelectionMerge %53 None + OpSwitch %21 %34 196153896 %53 20856160 %34 33570306 %34 593494531 %52 + %55 = OpLabel + OpLoopMerge %52 %58 DontUnroll + OpBranch %35 + %58 = OpLabel + OpSelectionMerge %58 None + OpSwitch %21 %52 178168 %55 608223677 %34 604111047 %34 -553516825 %34 -106432813 %BAD 6946864 %55 1257373689 %55 973090296 %35 -113180668 %55 537002232 %BAD 13762553 %BAD 1030172152 %35 -553516825 %55 -262137 %35 -1091822332 %BAD 131320 %52 131321 %35 131320 %52 131321 %35 -1091822332 %BAD + %53 = OpLabel + OpBranch %35 + %52 = OpLabel + OpBranch %34 + %35 = OpLabel + OpBranch %33 + %34 = OpLabel + OpKill + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("exits the selection headed by <ID> '3[%BAD]', but not " + "via a structured exit")); +} + } // namespace } // namespace val } // namespace spvtools |