The four graduated pin families byte-compared under test-data-byteid but their original fixtures masked the miscompiles at runtime (lone frame slot, dead code path, pointer accident). Add the discriminating programs as run fixtures: adjacent-element clobber for the 2-byte deref store, second-variant match dispatch for fn-type dedup, payload integrity across the tagged widen of a padded struct, and base64 clear() actually zeroing its buffers. Corpus pins move to 1,229 fixtures / 137 run / 766 run-exit / 2,458 cells with the new identity hash; the data-byteid floor moves to 915.
37 lines
1.0 KiB
Plaintext
37 lines
1.0 KiB
Plaintext
//ww:run
|
|
// probe: after io.close flushes the encoder, encode_closer calls
|
|
// clear(e) = bytes.zero(e.ibuf); bytes.zero(e.obuf). Under a correct
|
|
// build, ibuf/obuf are all zero afterwards. Under the wwstage
|
|
// miscompile the zeroing slice has len 0 -> stale bytes survive.
|
|
package main;
|
|
import encoding.base64;
|
|
import io;
|
|
import memio;
|
|
export fn main() int = {
|
|
let out: memio.stream = memio.dynamic();
|
|
let e: base64.encoder = base64.newencoder(&base64.std_encoding, &out.vt);
|
|
let raw: [5]u8 = ['f', 'o', 'o', 'b', 'a'];
|
|
match (io.write(&e.vt, raw)) {
|
|
case let n: size => void;
|
|
case let er: io.error => return 2;
|
|
};
|
|
match (io.close(&e.vt)) {
|
|
case void => void;
|
|
case let er: io.error => return 3;
|
|
};
|
|
// 5 = 3+2: the trailing 2-byte group went through the closer's
|
|
// pad path, so both ibuf and obuf held nonzero bytes before
|
|
// clear(). All must now read zero.
|
|
let i: i32 = 0;
|
|
for (i < 3) {
|
|
if (e.ibuf[i] != 0u8) { return (10 + i): int; };
|
|
i += 1;
|
|
};
|
|
i = 0;
|
|
for (i < 4) {
|
|
if (e.obuf[i] != 0u8) { return (20 + i): int; };
|
|
i += 1;
|
|
};
|
|
return 0;
|
|
};
|