formatter: avoid crash on attribute instance in for-loop header TreeUnwrapper::ReshapeTokenPartitions' kForSpec case assumed the for-loop header always yields two semicolon-leading partitions and CHECK-failed (SIGABRT) otherwise. An attribute instance ((* ... *)) in the for-loop init/condition changes the partition structure so those partitions are absent, aborting the formatter on otherwise valid input, e.g.: module m; initial for(int i=0(* a *);i<4;i++) x=i; endmodule Replace the two CHECKs with graceful early-outs: when a required semicolon-leading partition is not found, leave the partitions unreshaped instead of aborting. Normal for-loops (both partitions present) reshape exactly as before. Adds a formatter regression test. Signed-off-by: Eylon Krause <eylon1909@gmail.com>
diff --git a/verible/verilog/formatting/formatter_test.cc b/verible/verilog/formatting/formatter_test.cc index 5205a01..f9bb19e 100644 --- a/verible/verilog/formatting/formatter_test.cc +++ b/verible/verilog/formatting/formatter_test.cc
@@ -4707,6 +4707,15 @@ " for (int i = 0; i < f(m); i--) begin\n" " end\n" "endfunction\n"}, + {// for loop with an attribute instance in the initializer. + // Regression: this used to abort with a CHECK failure while reshaping + // the kForSpec partitions when an attribute appears in the header. + "module m; initial for(int i=0(* a *);i<4;i++) x=i; endmodule", + "module m;\n" + " initial\n" + " for (int i = 0 (* a *); i < 4; i++)\n" + " x = i;\n" + "endmodule\n"}, {// forever loop "function\nvoid\tforevah;forever begin " "++k\n;end endfunction\n",
diff --git a/verible/verilog/formatting/tree-unwrapper.cc b/verible/verilog/formatting/tree-unwrapper.cc index a6601ac..c373590 100644 --- a/verible/verilog/formatting/tree-unwrapper.cc +++ b/verible/verilog/formatting/tree-unwrapper.cc
@@ -2990,10 +2990,15 @@ auto &children = partition.Children(); const auto iter1 = std::find_if(children.begin(), children.end(), PartitionStartsWithSemicolon); - CHECK(iter1 != children.end()); + // An attribute instance ((* ... *)) in the for-loop header can change + // the partition structure so that the expected semicolon-leading + // partitions are not present. When they are missing, leave the + // partitions unreshaped rather than aborting (avoids a CHECK-failure + // crash on attributed/unusual for-headers). + if (iter1 == children.end()) break; const auto iter2 = std::find_if(iter1 + 1, children.end(), PartitionStartsWithSemicolon); - CHECK(iter2 != children.end()); + if (iter2 == children.end()) break; const int dist1 = std::distance(children.begin(), iter1); const int dist2 = std::distance(children.begin(), iter2); VLOG(4) << "kForSpec got ';' at child " << dist1 << " and " << dist2;