Skip to content

U1(functional-hardening): aggregate/field ARC matrix + seeded S1 fix - #131

Open
benpayne wants to merge 2 commits into
masterfrom
epic/functional-hardening/u1-arc-matrix
Open

U1(functional-hardening): aggregate/field ARC matrix + seeded S1 fix#131
benpayne wants to merge 2 commits into
masterfrom
epic/functional-hardening/u1-arc-matrix

Conversation

@benpayne

Copy link
Copy Markdown
Owner

Unit U1 — Aggregate/field ARC matrix (REQ-001) + seeded S1 fix (REQ-005)

Epic: functional-hardening · Spec: `specs/017-arc-matrix/spec.md` (approved, SPEC-1/SPEC-2 folded in)

Seeded bug S1 fixed — struct-valued field reassignment

o.inner = Inner { v: 99 } read back inconsistently. Root cause (SPEC-2): a read-path-dependent use-after-free, not a dropped store. The store landed, but CGStruct.cpp::genFieldAssignment had ARC ownership handling only for string/Array fields — a user-struct field fell into the bare else that just stored. The RHS struct temporary was __blang_rc_release'd at end of statement, freeing the block the field now pointed at. The first read could still see the value; any intervening allocation (notably the println/interpolation format path) reused the freed block, so subsequent reads returned stale data.

Fix: the struct-field = path now mirrors struct-literal initialization — take ownership of the new struct (untrack a fresh temporary, or rc_retain an existing-owner source) and release the previously-held struct, retain-before-release so self-assignment is safe. Valgrind-confirmed: pre-fix Invalid read of a freed block; post-fix clean.

ARC matrix — 7 codegen_arc_*.b (leak-glob prefix, load-bearing) + S1 regression

  • codegen_arc_string_field · codegen_arc_struct_field · codegen_arc_array_of_struct · codegen_arc_option_struct · codegen_arc_nested_writethrough · codegen_arc_self_assign · codegen_arc_map_struct_value (inline Map — no dependency on U4's S2)
  • codegen_struct_field_reassign.b — S1 regression. Per SPEC-1 it printlns the reassigned field twice under a committed golden; verified fails pre-fix (read1 1 / read2 0 + assert failure) and passes post-fix (all 99).
  • Every test has a committed stdout golden; all 8 are leak-clean under --leak-check (0 leaks).

Gates (reviewer: re-run independently)

  • ./test_codegen.sh93/0 (86 golden-checked, 7 quarantined); count 85 → 93
  • ./test_codegen.sh --leak-check test_files/codegen_arc_*.b test_files/codegen_struct_field_reassign.b8/8 CLEAN, Leaks: 0
  • ./run_tests.sh195/0; BUILD_DIR=build-parse ./run_tests.sh190/0
  • ctest --test-dir build54/54

Notes for the manager / U3

  • Soft conflict [U1,U3]: the S1 fix lands in CGStruct.cpp — per manager decision U1 is serialized before U3's CGStruct edits; U3 should rebase onto this merge.
  • Handoff to U3 (not filed): m.get(k).field — a field read directly off a generic method-call result (V→struct) — reads empty. This is U3's method-chain→field interaction shape (involves generic return-type monomorphization), not an ARC bug and not caused by this fix; the map test reads via a bound variable instead. Left for U3 rather than consuming a KI slot.
  • CLAUDE.md test-count bump is deferred to U5 close-out per the workplan (avoids U1–U4 all editing the same counter).

benpayne added 2 commits July 19, 2026 01:38
…pros

Baseline (green): run_tests 195 LLVM / 190 parse-only, test_codegen 85,
ctest 54, codegen_*.b=85. Seeded S1 (struct-field reassign) and S2 (Map via
module) reproduced. Spec lists 7 codegen_arc_*.b + codegen_struct_field_reassign.b.
Awaiting spec audit before implementation.
Fix S1 (REQ-005): struct-valued field reassignment 'o.inner = Inner{...}'.
Root cause was a read-path-dependent use-after-free, not a dropped store: the
store landed but genFieldAssignment had no ARC ownership handling for
user-struct fields (only string/Array), so the RHS struct temporary was
rc_release'd at end of statement, freeing the block the field now pointed at.
The first read could still see the value; an intervening allocation (the
println/interpolation format path) reused the freed block, so later reads were
stale. Fix mirrors struct-literal init: take ownership of the new struct
(untrack a fresh temp, or rc_retain an existing-owner source) and release the
previously-held struct, retain-before-release so self-assignment is safe.
Valgrind-confirmed: pre-fix Invalid read of freed block; post-fix clean.

ARC matrix (REQ-001): 7 codegen_arc_*.b tests (string-field, struct-field,
array-of-struct, option-struct, nested write-through, self-assign, map-struct-
value w/ inline Map) + codegen_struct_field_reassign.b (S1 regression, prints
the reassigned field under a golden so it FAILS pre-fix / passes post-fix per
SPEC-1). Each has a committed stdout golden; all 8 leak-clean under
--leak-check (0 leaks).

Gates: test_codegen 93/0 (86 golden-checked), run_tests 195 (LLVM) / 190
(parse-only), ctest 54/54. codegen_*.b 85 -> 93.
benpayne added a commit that referenced this pull request Jul 19, 2026
…unsigned byte (#132)

* functional-hardening: status -> ready (review passed 10/10)

* Launch functional-hardening on devbot: run 7708a1f6, status -> launched

* U1(arc-matrix): aggregate/field ARC matrix + seeded S1 fix (#131)

Squash-merge of epic/functional-hardening/u1-arc-matrix (reviewer-approved).

Fix seeded bug S1 (REQ-005): struct-valued field reassignment
'o.inner = Inner{...}'. Root cause was a read-path-dependent use-after-free —
genFieldAssignment had no ARC ownership handling for user-struct fields, so the
RHS struct temporary was rc_release'd at end of statement, freeing the block the
field now pointed at. Fix (CGStruct.cpp genFieldAssignment) mirrors struct-literal
init: take ownership of the new struct (untrack fresh temp / retain existing
owner) and release the previously-held struct, retain-before-release so
self-assignment is safe.

ARC matrix (REQ-001): 7 codegen_arc_*.b tests + codegen_struct_field_reassign.b
(S1 regression), each with committed stdout goldens; all 8 leak-clean under
--leak-check (0 leaks).

Reviewer audit: SPEC-1 teeth verified (S1 test fails pre-fix with stale 1/0,
passes post-fix with 99); SPEC-2 diagnosis verified (read-path UAF, not dropped
store). Gates re-run independently: run_tests 195 (LLVM)/190 (parse-only),
test_codegen 93/0 (86 golden-checked), ctest 54/54, leak-check 8/8 CLEAN.
codegen_*.b 85 -> 93. No KI filed; deferred generic-method-chain->field bug is a
U3 concern (generic-return-type, not ARC).

* U2(operator-matrix): spec — bitwise/shift/%/compound/short-circuit matrix + short-circuit fix

Grounding probe through real bcc found && / || do NOT short-circuit RHS side
effects (primary fix, CGExpressions.cpp:390-391 eager operand eval); byte
unsigned-shift/print discrepancy (fix-or-file). Concrete named golden cases:
codegen_op_{bitwise,shift,modulo,compound,short_circuit,byte}.b.

* U2 spec: fold in spec-audit suggestions (byte print is general, println path, precedence/~ confirmed); status Approved

* U2(operator-matrix): short-circuit && / || + unsigned byte ops, operator goldens

Fixes (CGExpressions.cpp genOperationsExpression):
- && / || now short-circuit: the RHS (and its side effects) is evaluated only
  when the LHS does not determine the result. Was: both operands eagerly
  evaluated, so RHS side effects always ran. Lowered as branch + i1 phi.
- byte is unsigned: byte operands widen with ZExt (not SExt), >> on a byte is a
  logical shift, and a byte prints unsigned (0-255) via the {} builtin. Matches
  the already-unsigned byte->int conversion (codegen_byte.b).

Tests (6 new codegen_op_*.b + committed stdout goldens): bitwise (& | ^, ~,
C precedence), shift (<< >>, arithmetic-right on negative int, 1<<30), modulo
(incl. negative dividend/divisor), compound (%= ^= += chains), short_circuit
(touch(n) side-effect ordering — golden shows only touch 2 & touch 4; fails
pre-fix), byte (unsigned bitwise/shift/print). codegen 93 -> 99.

Docs: language_design.md notes && / || short-circuit and byte unsigned semantics
(Principle I). Fix in CGExpressions.cpp only — no CGStruct.cpp (no U1/U3 conflict).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant