bufio: readahead signals overflow when it cannot grow (F-B)

The scanner readahead silently fell through when start==0 and the
buffer was full at maxread, producing no bytes and no error. scanbyte
then spun forever re-requesting bytes that never came (catB-144) and
scanrune nil-dereferenced s.ptr[s.start] (catB-145).

Make readahead the single overflow choke-point: at the ceiling it
returns a bufio-local `overflow` before the grow, propagated through
scanbyte/scanrune/scanbytes (scanbytes drops its now-redundant manual
pre-check). Mirrors ref/hare/bufio/scanner.ha:174-182, which returns
errors::overflow there; ww uses bufio-local overflow because io.error
is a closed enum without an overflow member. Consumers (regex, the 778
embedded source) gain the totality arm.

Table-driven @test crosses {nil-ptr, zero-len} x {scanbyte, scanrune};
neutralizing the overflow return reproduces the catB-144 hang.
This commit is contained in:
2026-06-14 11:54:20 +09:00
parent 1752305be7
commit 851915e6fe
4 changed files with 125 additions and 41 deletions

View File

@@ -1206,6 +1206,10 @@ fn search(
};
case let e: io.error => abort("regex: scanrune io error");
case utf8.invalid => abort("regex: scanrune invalid utf8");
// Unreachable: this scanner is newscanner(h, I32_MAX), so the
// can't-grow ceiling is never hit; the arm keeps the match
// total over scanrune's widened overflow surface (drain F-B).
case bufio.overflow => abort("regex: scanrune overflow");
};
if (r_or_end is rune) {
last_bytesize = (utf8.runesz(r_or_end as rune): size);