test/wcc/data: pin the drained divergences at runtime

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.
This commit is contained in:
2026-08-07 23:55:01 +09:00
parent 0b1cc5ef7c
commit 8a9be47f65
7 changed files with 94 additions and 9 deletions

View File

@@ -0,0 +1,9 @@
//ww:run-exit 42
package main;
fn setneg(p: *i16) void = { *p = -16i64: i16; };
fn main() i32 = {
let a: [4]i16 = [7i16, 7i16, 7i16, 7i16];
setneg(&a[0]);
if (a[0]: i64 == -16i64 && a[1] == 7i16 && a[2] == 7i16 && a[3] == 7i16) { return 42; };
return 1;
};

View File

@@ -0,0 +1,27 @@
//ww:run-exit 100
package main;
type small = struct { v: i32 };
fn consume(r: (void | small)) i32 = {
match (r) {
case void => return 1;
case let v: small => {
let p: *i64 = (&v): *i64;
let w: i64 = *p;
if (w == 7i64) { return 100; };
return 50;
};
};
return 0;
};
fn dirty() void = {
let x: i64 = -1i64;
};
fn probe() i32 = {
let s: small;
s.v = 7;
return consume(s);
};
fn main() i32 = {
dirty();
return probe();
};

View File

@@ -0,0 +1,13 @@
//ww:run-exit 7
package main;
fn a(x: i32) void = { };
fn b(x: i32, y: i64) void = { };
type t = (*fn(x: i32) void | *fn(x: i32, y: i64) void);
export fn main() i32 = {
let v: t = &b;
match (v) {
case *fn(x: i32) void => return 3;
case *fn(x: i32, y: i64) void => return 7;
};
return -1;
};

View File

@@ -0,0 +1,36 @@
//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;
};