test: migrate 933-939 str-cap family to test/lang @test
Fan out the str-cap read (933-936) and store (937-939) families into in-language @test files, following the 932 str_elem_cap template. Additive: the *_run.c stay in the C corpus (they are the only wwstage-runtime net for these cs==ww byte-id-blind shapes); de-dup deferred to fold 6. Per-shape @test fns, not a data table: each fn varies the codegen shape (base reg / chain depth / tuple return-ABI / store position), so the row-array idiom (blocked by #111) would lose coverage. Read family keeps the spoil()/register-clobber + junk==44 discrimination where the .c has it; store family pre-poisons the slot via a path distinct from the store under test. Asserts are primitives only.
This commit is contained in:
81
test/lang/str_arrfield_cap_test.ww
Normal file
81
test/lang/str_arrfield_cap_test.ww
Normal file
@@ -0,0 +1,81 @@
|
||||
// str_arrfield_cap_test — a str-typed FIELD of an INDEXED element `arr[i].f`
|
||||
// (N_INDEX-rooted N_DOT) must load the full 24B {ptr,len,cap} header, not just
|
||||
// {ptr,len}, migrated from test/wcc/936_str_arrfield_cap_run.c (C4.6 arrfield,
|
||||
// the LAST member of the 3-word-value-read cluster). str is 24B since Phase 2
|
||||
// (#1); pre-arrfield the `arr[i].f` str arm loaded 2 words (len in BX, ptr in
|
||||
// AX) and dropped cap. The miscompile was cs==ww, so the 990-997 byte-id gates
|
||||
// stayed GREEN while the runtime was wrong — behavioral @test is the net. There
|
||||
// is no adjacent slice-element sibling at this leaf, so the 3-word triple is
|
||||
// authored directly to the canonical slice-header ABI (len->BX, cap->CX,
|
||||
// ptr->AX LAST).
|
||||
//
|
||||
// POISONING: the store side of `arr[i].f = v` is a separate, still-broken
|
||||
// store-side gap (filed; out of scope for this read-side fold). So the value
|
||||
// elements (A, B) are poisoned through `&arr[i]` + a *struct field write, which
|
||||
// lands a real cap into the element's +16 word; D points its element at a
|
||||
// separately-built struct (the proven s1local 3-word field store).
|
||||
//
|
||||
// DISCRIMINATION: a 2-word read leaves CX holding whatever the index scale-
|
||||
// multiply left there, never the poison; spoil() additionally interposes a
|
||||
// CX-clobbering call between the build and the `arr[i].f` read, so a broken
|
||||
// 2-word read observes spoil's leftover (44), never the poison cap.
|
||||
|
||||
package str_arrfield_cap_test;
|
||||
|
||||
type rec = struct { f: str };
|
||||
|
||||
fn spoil() i32 = {
|
||||
let z: str = "zzzz";
|
||||
z.cap = 44i32;
|
||||
let w: str = z;
|
||||
return w.cap: i32;
|
||||
};
|
||||
|
||||
@test fn arrfield_array_value() void = {
|
||||
// A — `arr[i].f` value element of a [N]rec local array (LEAQ base).
|
||||
// Poison cap=8 (len=2) via &arr[1] + a *struct field store.
|
||||
let p: str = "hi";
|
||||
p.cap = 8i32;
|
||||
let arr: [3]rec;
|
||||
let pr: *rec = &arr[1];
|
||||
pr.f = p;
|
||||
let junk: i32 = spoil();
|
||||
let s: str = arr[1].f;
|
||||
assert(s.cap: i32 == 8);
|
||||
assert(s.len: i32 == 2);
|
||||
assert(junk == 44);
|
||||
};
|
||||
|
||||
@test fn arrfield_slice_value() void = {
|
||||
// B — `sl[i].f` value element of a []rec local slice (MOVQ slice.ptr
|
||||
// base) viewing the same poisoned backing array. Poison cap=9 (len=5).
|
||||
let p: str = "world";
|
||||
p.cap = 9i32;
|
||||
let arr: [3]rec;
|
||||
let pr: *rec = &arr[1];
|
||||
pr.f = p;
|
||||
let sl: []rec = arr[0:3];
|
||||
let junk: i32 = spoil();
|
||||
let s: str = sl[1].f;
|
||||
assert(s.cap: i32 == 9);
|
||||
assert(s.len: i32 == 5);
|
||||
assert(junk == 44);
|
||||
};
|
||||
|
||||
@test fn arrfield_ptr_elem() void = {
|
||||
// D — `arr[i].f` pointer element of a [N]*rec array (LEAQ base, MOVQ
|
||||
// deref to the *rec, then the leaf field load). The element points at a
|
||||
// separately-built struct so the poison rides the proven s1local 3-word
|
||||
// field store, not the broken array-element store. Poison cap=7 (len=3).
|
||||
let p: str = "abc";
|
||||
p.cap = 7i32;
|
||||
let st: rec;
|
||||
st.f = p;
|
||||
let arr: [3]*rec;
|
||||
arr[1] = &st;
|
||||
let junk: i32 = spoil();
|
||||
let s: str = arr[1].f;
|
||||
assert(s.cap: i32 == 7);
|
||||
assert(s.len: i32 == 3);
|
||||
assert(junk == 44);
|
||||
};
|
||||
Reference in New Issue
Block a user