An early return inside a loop sets a flag the loop never reads, so the loop keeps going -- and one of them does not terminate
The Verilog backend lowers return inside a loop body as "assign the function's
return variable, set __t27_ret", and guards only the FUNCTION-TAIL return with
if (!__t27_ret). Nothing guards the loop. Verbatim from
gen-verilog specs/isa/ternary_search.t27:
while ((lo < hi)) begin
mid = (lo + ((hi - lo) / 2));
if ((data[mid] == target)) begin
binary_search = $signed(mid);
__t27_ret = 1'b1; // <-- flag set, loop NOT exited,
end else if ((data[mid] < target)) begin // lo and hi unchanged
lo = (mid + 1);
end else begin
hi = mid;
end
end
if (!__t27_ret) begin
binary_search = -1;
__t27_ret = 1'b1;
end
On a hit neither lo nor hi moves, so while ((lo < hi)) spins forever.
On a miss it terminates and is correct.
linear_search in the same file has the terminating variant of the same defect:
it runs to the end of the array and returns the LAST match where the source says
the first.
Population
55 sites across 24 of the 581 generated .v files (a scan tracking begin/end
depth from each loop header and counting __t27_ret = 1'b1; inside). Largest:
specs_math_property_test_template.v 11, specs_compiler_stdlib.v 8,
specs_isa_ternary_hash.v 5, specs_pins_ir.v 4.
55 is the size of the CLASS, not 55 proven-wrong values. An early return in a
loop is only wrong when the loop can iterate again afterwards; the detector
over-counts by construction and this number should not be quoted as defects.
Two functions were read end to end and are demonstrably wrong.
C, Rust and Zig all return the first match on the same source.
Why nothing reported it
All 24 files fail iverilog today for unrelated reasons, and the one deep ruler
that would run them has had zero targets -- #2987. A non-terminating simulation
is also invisible to a compile-only gate by construction.
The repair is the same missing machinery as #2988: a named block per loop, so
the flag can disable it. Filing them separately because the populations differ
and the wrong-value consequence here is silent rather than a no-op.
An early
returninside a loop sets a flag the loop never reads, so the loop keeps going -- and one of them does not terminateThe Verilog backend lowers
returninside a loop body as "assign the function'sreturn variable, set
__t27_ret", and guards only the FUNCTION-TAIL return withif (!__t27_ret). Nothing guards the loop. Verbatim fromgen-verilog specs/isa/ternary_search.t27:On a hit neither
lonorhimoves, sowhile ((lo < hi))spins forever.On a miss it terminates and is correct.
linear_searchin the same file has the terminating variant of the same defect:it runs to the end of the array and returns the LAST match where the source says
the first.
Population
55 sites across 24 of the 581 generated
.vfiles (a scan tracking begin/enddepth from each loop header and counting
__t27_ret = 1'b1;inside). Largest:specs_math_property_test_template.v11,specs_compiler_stdlib.v8,specs_isa_ternary_hash.v5,specs_pins_ir.v4.55 is the size of the CLASS, not 55 proven-wrong values. An early return in a
loop is only wrong when the loop can iterate again afterwards; the detector
over-counts by construction and this number should not be quoted as defects.
Two functions were read end to end and are demonstrably wrong.
C, Rust and Zig all return the first match on the same source.
Why nothing reported it
All 24 files fail
iverilogtoday for unrelated reasons, and the one deep rulerthat would run them has had zero targets -- #2987. A non-terminating simulation
is also invisible to a compile-only gate by construction.
The repair is the same missing machinery as #2988: a named block per loop, so
the flag can
disableit. Filing them separately because the populations differand the wrong-value consequence here is silent rather than a no-op.