Refusing to encode is a claim about the buffer, and nothing was checking it
encode-rune! says nothing is written when it answers None, and every None case in the table passed that claim without testing it: an encoder that lays the lead byte down and only then notices the buffer is short returns None exactly as a correct one does. So a known byte goes into scratch, a refused encoding is asked for, and the byte is read back. Storing before the length test turns the line from 65 -1 65 -1 65 into 65 -1 0 -1 0. The read-only claim beside lower-ascii was reasoned from the emitted linkage rather than observed, and observing it was worse than the guess. With (set (at (bytes "Hi") 0) \h): at -O0 the store is emitted against the constant and the program takes SIGSEGV; at -O2 LLVM deletes it as undefined behaviour and the program prints "Hi" and exits 0. The same source either dies or silently does nothing depending on a flag. The comment now says that instead of predicting a segfault.
This commit is contained in:
parent
4957497d02
commit
ecf3882fa2
@ -637,11 +637,22 @@ let source = {flan|
|
||||
;; to_upper both allocate a new string (core/strings/conversion.odin), which
|
||||
;; is not available here; the obvious substitute — lowering a [u8] in place —
|
||||
;; is a trap, and it is worth saying why rather than shipping it. A string
|
||||
;; literal is emitted `private unnamed_addr constant` (emit.ml), so it lives
|
||||
;; in read-only memory, and (bytes "Hello") is a [u8] pointing straight at it.
|
||||
;; An in-place lower-ascii! would type check against that slice and segfault
|
||||
;; on the store. Given a byte function, a caller that really does own its
|
||||
;; buffer writes the two-line loop itself and can see what it is writing to.
|
||||
;; literal is emitted `private unnamed_addr constant` (emit.ml), so (bytes
|
||||
;; "Hello") is a [u8] pointing straight into read-only memory. An in-place
|
||||
;; lower-ascii! type checks against that slice, and what happens next depends
|
||||
;; on the optimiser — which is the worst of the available answers. Measured,
|
||||
;; with (set (at (bytes "Hi") 0) \h):
|
||||
;;
|
||||
;; -O0 the store is emitted against the constant and the program takes
|
||||
;; SIGSEGV.
|
||||
;; -O2 LLVM deletes the store as undefined behaviour and the program
|
||||
;; carries on and prints "Hi".
|
||||
;;
|
||||
;; So the same source either dies or silently does nothing depending on a
|
||||
;; flag, and the -O2 half is the quiet-wrongness class this file keeps
|
||||
;; refusing elsewhere. Given a byte function instead, a caller that really
|
||||
;; does own its buffer writes the two-line loop itself over storage it can
|
||||
;; see the declaration of.
|
||||
;;
|
||||
;; ASCII only, and only the 26 letters: case outside ASCII is not a byte
|
||||
;; operation at all — it is per-code-point, it is not length-preserving (ß
|
||||
|
||||
@ -190,6 +190,19 @@
|
||||
(show-opt (encode-rune! (slice scratch 0 1) 0x41)) ; 1, exactly enough
|
||||
(newline)
|
||||
|
||||
;; "Nothing is written when it refuses" is a claim about the buffer, not
|
||||
;; about the return value, and the None cases above do not test it: an
|
||||
;; encoder that lays down the lead byte and only then notices the buffer is
|
||||
;; short returns None exactly as this one does, and every line above still
|
||||
;; passes. So put a known byte in scratch, ask for an encoding that must be
|
||||
;; refused, and read the byte back.
|
||||
(show-i32 (round-trip 0x41)) ; 65, scratch[0] = A
|
||||
(show-opt (encode-rune! (slice scratch 0 2) 0x65e5)) ; -1, needs 3 bytes
|
||||
(show-i32 (i32 (at scratch 0))) ; 65 still
|
||||
(show-opt (encode-rune! (slice scratch 0 4) 0xd800)) ; -1, surrogate
|
||||
(show-i32 (i32 (at scratch 0))) ; 65 still
|
||||
(newline)
|
||||
|
||||
;; Splitting. n separators give n+1 fields, always: an interior empty field
|
||||
;; survives, a leading and a trailing one do too, and an input with no
|
||||
;; separator at all is one field rather than none. The empty input is the
|
||||
|
||||
@ -913,6 +913,7 @@ ERR@7 unexpected token: not the kind the caller was reading
|
||||
-1 1 1 2 2 3 3 -1 -1 3 3 4 4 -1 \n\
|
||||
0 65 127 128 2047 2048 65535 65536 1114111 \n\
|
||||
-1 -1 -1 -1 -1 1 \n\
|
||||
65 -1 65 -1 65 \n\
|
||||
[a][b][c] [a][][b] [abc] [] [][] [][a] [a][] \n\
|
||||
60\n\
|
||||
97 122 97 64 91 65 90 65 96 123 53 \n\
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user