A mutation run found the four-byte overlong nobody was testing

Relaxing 0xf0's second-byte floor from 0x90 to 0x80 left the whole suite
green: every other row of the table had a case pinning it and that one did
not, so f0 80 80 af decoded happily as "/". The same smuggled slash the
two- and three-byte cases exist to catch, missed in the fourth width.

Seven mutations verified red after this: the lead-byte floor at 0xc2 and the
second-byte bounds on 0xe0, 0xed, 0xf0 and 0xf4, the truncated-sequence
width, and the split cursor dropping its trailing empty field. An eighth,
lower-ascii written as a bit-xor, is red on the bytes either side of the
letters — which is why those are in the table and the letters alone are not.
This commit is contained in:
Joseph Ferano 2026-09-12 03:56:40 +07:00
parent 273dd18eb0
commit 4957497d02
2 changed files with 5 additions and 1 deletions

View File

@ -28,6 +28,7 @@
(defconst overlong2 [2 u8] [0xc0 0xaf])
(defconst overlong3 [3 u8] [0xe0 0x80 0xaf])
(defconst overlong4 [4 u8] [0xf0 0x80 0x80 0xaf])
(defconst surrogate [3 u8] [0xed 0xa0 0x80])
(defconst above-max [4 u8] [0xf4 0x90 0x80 0x80])
(defconst lead-f5 [4 u8] [0xf5 0x80 0x80 0x80])
@ -101,6 +102,9 @@
(show-dec (slice lone-cont 0 1)) ; a continuation byte leading
(show-dec (slice overlong2 0 2)) ; overlong "/"
(show-dec (slice overlong3 0 3)) ; overlong "/" again, three bytes
(show-dec (slice overlong4 0 4)) ; and four. Added after a mutation run:
; relaxing 0xf0's floor to 0x80 left the
; whole suite green without this line.
(show-dec (slice surrogate 0 3)) ; U+D800
(show-dec (slice above-max 0 4)) ; U+110000
(show-dec (slice lead-f5 0 4)) ; 0xf5 leads nothing

View File

@ -904,7 +904,7 @@ ERR@7 unexpected token: not the kind the caller was reading
shared. *)
let utf8_out =
"0/0/f 65/1/t 233/2/t 26085/3/t 128512/4/t \n\
0/1/f 0/1/f 0/1/f 0/1/f 0/1/f 0/1/f \n\
0/1/f 0/1/f 0/1/f 0/1/f 0/1/f 0/1/f 0/1/f \n\
0/1/f 0/1/f 0/1/f 0/1/f \n\
tft\n\
0 3 8 13 3\n\