Prevent null pointer from being dereferenced (#4971)

Fixes https://crbug.com/oss-fuzz/48553

* Assign a reflexive dominator if no other dominator can be found using
  forward traversals
  * This prevents a null dereference of a pointer in the sorting of the
    output
diff --git a/source/cfa.h b/source/cfa.h
index 2743ab4..9ae3e39 100644
--- a/source/cfa.h
+++ b/source/cfa.h
@@ -275,10 +275,16 @@
 
   std::vector<std::pair<bb_ptr, bb_ptr>> out;
   for (auto idom : idoms) {
+    // At this point if there is no dominator for the node, just make it
+    // reflexive.
+    auto dominator = std::get<1>(idom).dominator;
+    if (dominator == undefined_dom) {
+      dominator = std::get<1>(idom).postorder_index;
+    }
     // NOTE: performing a const cast for convenient usage with
     // UpdateImmediateDominators
     out.push_back({const_cast<BB*>(std::get<0>(idom)),
-                   const_cast<BB*>(postorder[std::get<1>(idom).dominator])});
+                   const_cast<BB*>(postorder[dominator])});
   }
 
   // Sort by postorder index to generate a deterministic ordering of edges.
diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp
index a4d1444..c8dd4a2 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -4601,6 +4601,33 @@
                 "does not structurally dominate the back-edge block '8[%8]'"));
 }
 
+TEST_F(ValidateCFG, BadLoop) {
+  const std::string text = R"(
+OpCapability Shader
+OpMemoryModel Logical Simple
+OpEntryPoint Fragment %2 "           "
+OpExecutionMode %2 OriginUpperLeft
+OpName %49 "loop"
+%void = OpTypeVoid
+%12 = OpTypeFunction %void
+%2 = OpFunction %void None %12
+%33 = OpLabel
+OpBranch %49
+%50 = OpLabel
+OpBranch %49
+%49 = OpLabel
+OpLoopMerge %33 %50 Unroll
+OpBranch %49
+OpFunctionEnd
+)";
+
+  CompileSuccessfully(text);
+  EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr("Loop header '2[%loop]' is targeted by 2 back-edge "
+                        "blocks but the standard requires exactly one"));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools