aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralan-baker <alanbaker@google.com>2022-12-06 11:22:33 -0500
committerGitHub <noreply@github.com>2022-12-06 11:22:33 -0500
commit9c6a925c87d4c6e203e440ecc8a57018e5bb8c4b (patch)
tree834cdf10853a11cdf13152d2934817fdc9c13922
parent7b8f00f00a5b18374a294f728ec87565c2fc4ca1 (diff)
downloadspirv-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.cpp4
-rw-r--r--source/val/validate_cfg.cpp1
-rw-r--r--test/val/val_cfg_test.cpp44
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