You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Evaluate wide constant indexes without truncation #154
Compiler audit reproduced wide constant fixed-array indexes being normalized to default i32 before bounds checking. A known out-of-bounds index can become an in-bounds value and silently select the wrong element.
This is separate from constant binding identity fixed in commit 80b3fd3.
Audited baseline: cfcae13, Linux/amd64, Go 1.26.8, Clang 22.1.8.
Observed: check and build succeed. Native output is 99, then 4294967296; published constant-index evidence is zero.
Expected: reject known out-of-bounds index 4294967296 for a one-element fixed array. Bounds validation must preserve the checked index's value.
Existing owners and cause
internal/semantics/typechecker/check_expr.go, typeIndexExpr: constant evaluation requests DefaultIntegerType() instead of the actual checked index type.
internal/semantics/typechecker/constant_eval.go, expectedNumericConstValue: integral normalization can truncate the binding to that expected width.
Existing constant-index evidence, bounds diagnostics, and target representability checks should remain the canonical paths.
Acceptance criteria
Preserve checked integer width and value during index constant evaluation.
Reject known invalid fixed-array indexes without truncation or host-sized parsing changing their meaning.
Preserve runtime index guards, canonical resolved bindings, and source diagnostic context.
Cover signed/unsigned boundaries, wider positive/negative constants, and bindings versus direct expressions.
Validate affected 32-/64-bit target representability and LLVM lowering.
Add focused evidence/bounds regressions and positive/negative x_test/ fixtures, executed with rebuilt bundled compiler.
Keep this a focused follow-up; reassess coupling with numeric constant publication only if the implementation genuinely requires one shared evaluator change.
Local checked-index repair
The default-i32 constant-query narrowing is fixed locally on fix/constant-numeric-publication as part of the approved #155 review follow-up. typeIndexExpr now passes its already-checked indexType to the existing evaluator. This repairs both the original bound-wide-index repro and newly supported float-cast indexes at their shared owner; no parallel evaluator or cast-specific workaround is added.
Focused regressions preserve exact signed/unsigned values, including u64 max and u128 beyond host integer size, and verify source-located T0009 bounds diagnostics. Local wide positive/negative bindings and float casts are rejected before MIR on Linux/386 and amd64. Positive typed projections compile with Clang on both targets; runtime fixture preserves u8 negation, explicit narrowing and imported alias values. Positive/negative bundled fixtures proved red before repair and pass after rebuilding.
Changed/affected packages, full executable-fixture Go suite, vet, focused race, formatting and diff checks pass. That first local repair changed the constant bounds-query context; its validation is historical. The exact-length follow-up below also repairs the shared runtime element guard. Local implementation is uncommitted and awaits review/landing, so this issue remains open.
Local exact-bounds follow-up
Completed locally on fix/constant-numeric-publication in the approved #155/#154 review follow-up. Source bounds now compare exact integers, without host-sized length or index parsing. LLVM retains unsigned 64-bit array lengths, compares constant indexes exactly, and keeps index source locations for backend bounds rejection. The shared runtime element guard independently rejects negative signed indexes, including when unsigned length exceeds 2^63. Existing normalization, checked evidence, resolved bindings and trap-before-access ordering remain.
Red/green coverage: three source-located pre-MIR rejection cases; six backend constant/malformed boundaries; constant/runtime borrowed-field LLVM compiled by Clang for 386 length 2^31 and amd64 lengths 2^63 and 2^63+1; eight native guard executions covering signed negatives, valid high unsigned indexes, equality and wider integers. New positive/negative large-array fixtures pass with rebuilt bundle. Large arrays are symbolic; huge-object allocation is not claimed.
Final validation passed with CCACHE_DISABLE=1: focused and affected packages; bundle rebuild and seven affected fixture contracts; full PEEPER_BIN=/home/itsfuad/Dev/Peeper/compiler/build/bin/peeper go test -count=1 ./... (all executable fixtures 21.190s); go vet ./...; typechecker/pipeline/LLVM race tests; formatting and diff checks. All eight #155 review items resolved locally, including three test/evidence simplifications. Implementation remains uncommitted and awaits review/landing; issue stays open.
Local narrow-unsigned GEP follow-up
Completed locally on fix/constant-numeric-publication (STEP 1E / review finding 11). Newly folded 1f64 as u1 selected a negative LLVM offset because GEP sign-extends narrow operands. After exact constant bounds validation, emitIndexPtr now reuses existing emitCast to produce an i64 physical offset. Source/MIR checked type and value, unsigned lengths, located malformed/OOB rejection and runtime guards remain intact. No new production helper, API or state.
Permanent red proof: 12 u1/u8/u24 read/store failures across 386/amd64, with 4 u64 controls passing; 18 source-to-MIR conversion failures; previous bundled fixture builds then exits 8 at wrong-element read. Green coverage: 36 backend read/store cases, 24 source/MIR/LLVM/Clang cases across both widths (including top-bit u8/u24 borrowed fields), and native fixture reads, stores, borrows and raw addresses selecting the correct slot while preserving guard/neighbor values.
Validation passed with CCACHE_DISABLE=1: changed/affected packages; bundle rebuild; 18 affected positive/negative/trap/place/slice fixture contracts; full PEEPER_BIN=/home/itsfuad/Dev/Peeper/compiler/build/bin/peeper go test -count=1 ./... (executable fixtures 19.622s, LSP 38.816s); go vet ./...; LLVM/pipeline/IR race checks; formatting, diff and rule audit. 386 is IR/object validation, not native execution; large-array controls are symbolic.
Latest disposition: earlier findings 1-8 plus 11 fixed locally; 9 (single-use ABI helper), optional 10 (duplicate cast adaptation), and 12 (qualified imported constant bounds) remain Proposed with full repair plan. Qualified known-OOB gap remains tracked by #154; no completeness claim for that path. Implementation uncommitted and awaiting step review/landing; issues remain open.
Local qualified-constant follow-up
STEP 1F / review finding 12 is fixed locally on fix/constant-numeric-publication, following user approval of STEP 1E. Existing evaluator symbol-read case now accepts Ident and ScopeResolution and queries original occurrence binding. SymbolConst gate, evalConstSymbol, defining-module PublishedConstant and numeric adaptation remain canonical. Variant dispatch stays first; no new production helper/API/state/store, foreign consumer cache, AST re-evaluation or lexical/import lookup fallback.
Permanent red/green proof: 30 real-import index cases on Linux/386 and amd64 (16 exact source-located bounds errors before MIR/LLVM, 14 typed THIR/MIR positive cases including aliases, transitive publication, u1, source-width negation and narrowing), 8 shifts, 8 range width/entry/missing-return cases and 3 conditions whose warning appears exactly once at CFG, not Typechecked. Foreign-owner controls preserve published value after owner AST changes, reject missing publication despite poisoned cache, and keep unbound/nonconstant paths unsuccessful. Previous bundle missed imported errors and rejected valid consumer statics; rebuilt bundle passes new negative imported-query fixture and native imported u1 borrow/store, integer/float consumer-static and qualified-default/caller-shadow controls. Existing cache/cycle/default/fingerprint/enum/place behavior passes.
Final validation passed with CCACHE_DISABLE=1: changed/affected packages; 386/amd64 LLVM/Clang objects; bundle rebuild; 27 affected fixture contracts; full suite with rebuilt PEEPER_BIN (all executable fixtures 46.738s, LSP 40.247s); go vet ./...; typechecker/project/pipeline/IR/LLVM race checks; formatting/diff/rule audit. Two test-local helpers consolidate real-file/import setup and shared THIR/MIR evidence assertions, removing copied traversal. Native execution is amd64; 386 is object validation and large-array controls are symbolic.
Disposition: findings 1-8 and 11/12 Fixed locally; 9 (ABI helper) and optional 10 (duplicate cast adaptation) remain Proposed. STEP 1F awaits review; implementation uncommitted and issues remain open pending landing. Separate pre-existing parser ambiguity for bare qualified range endpoints before loop braces is tracked in #157; casted endpoints isolate evaluator tests. No parser repair or completeness claim for that syntax in this checkpoint.
Local ABI/cast cleanup and combined review
User-approved combined STEP 1G/1H is complete locally on fix/constant-numeric-publication. Finding 9: ABIKey now owns nominal-key/text fallback directly; single-use abiKeyLocked deleted. Existing nil/invalid-ID guards, one read lock and raw reserved-shell access remain intact. Finding 10: explicit numeric cast returns its successfully validated value when canonical target/context types match; differing/nil queries and captured deferred destination conversion remain. Source-width intermediates, narrowing before widening, aliases/byte distinction, IEEE results and invalid-value rejection are preserved. No new production helper/API/state/instrumentation or performance claim.
Meaningful invariant coverage passed both before and after cleanup: reserved-shell ABI identity before completion (public Type remains incomplete), inferred alias/byte casts without typing evidence, differing u16 context, aliased f32-to-f64 rounding and negative-zero widening. Existing imported constants, cache/cycles/finalization, exact bounds, source/MIR index types, guarded places, nominal/static-address and default/fingerprint contracts remain tested.
Final validation passed with CCACHE_DISABLE=1: focused and affected packages; Linux/386 and amd64 LLVM/Clang checks; bundle rebuild; 28 affected executable fixture contracts; full PEEPER_BIN=/home/itsfuad/Dev/Peeper/compiler/build/bin/peeper go test -count=1 ./... (executable fixtures 21.924s, LSP 38.820s); go vet ./...; IR/typechecker/project/pipeline/LLVM race checks; formatting/diff/deleted-helper/rule audits. Independent Standards review found zero hard violations and zero optional smells; independent Spec review found zero actionable defects and independently reran selected IR/typechecker/pipeline tests including numeric statics, recursive enums and interface consumers.
Disposition: all 12 constant-evaluation review findings Fixed locally; supplemental target-reuse cleanup also Fixed. Implementation remains uncommitted and awaits human review/landing; this issue remains OPEN in 0.2 Language Foundations. PR #156 merge remains deferred. Native execution is amd64; 386 is object validation and large-array controls are symbolic. Parser issue #157 and other original audit work remain separate. Roadmap linkage retains existing token-scope blocker; no credential changes.
PR publication
Reviewed implementation is now published in PR #158: #158. Earlier local-progress sections preserve checkpoint history; the implementation is now committed and pushed.
Latest local validation passed after final cleanup: focused IR/typechecker, affected IR/pipeline/LLVM on Linux/386 and amd64, bundle rebuild, full rebuilt-compiler executable-fixture suite (fixtures 13.354s, LSP 38.414s), formatting and diff checks. Earlier vet/race results remain separately recorded. No source changed after validation.
PR title/body, foundation milestone, both commits and exact thirty-six-file scope verified. Hosted main CI and self-review workflows target main, so their checks await retargeting; no non-author human approval recorded.
Issue remains OPEN pending landing. Parser Disambiguate qualified range endpoints from loop bodies #157 and other original audit work remain separate. Roadmap association retains the known read:project permission blocker; credentials/config unchanged.
Problem
Compiler audit reproduced wide constant fixed-array indexes being normalized to default
i32before bounds checking. A known out-of-bounds index can become an in-bounds value and silently select the wrong element.This is separate from constant binding identity fixed in commit
80b3fd3.Audited baseline:
cfcae13, Linux/amd64, Go 1.26.8, Clang 22.1.8.Reproduction
Observed:
checkand build succeed. Native output is99, then4294967296; published constant-index evidence is zero.Expected: reject known out-of-bounds index
4294967296for a one-element fixed array. Bounds validation must preserve the checked index's value.Existing owners and cause
internal/semantics/typechecker/check_expr.go,typeIndexExpr: constant evaluation requestsDefaultIntegerType()instead of the actual checked index type.internal/semantics/typechecker/constant_eval.go,expectedNumericConstValue: integral normalization can truncate the binding to that expected width.Acceptance criteria
x_test/fixtures, executed with rebuilt bundled compiler.Keep this a focused follow-up; reassess coupling with numeric constant publication only if the implementation genuinely requires one shared evaluator change.
Local checked-index repair
The default-i32 constant-query narrowing is fixed locally on
fix/constant-numeric-publicationas part of the approved #155 review follow-up.typeIndexExprnow passes its already-checkedindexTypeto the existing evaluator. This repairs both the original bound-wide-index repro and newly supported float-cast indexes at their shared owner; no parallel evaluator or cast-specific workaround is added.Focused regressions preserve exact signed/unsigned values, including u64 max and u128 beyond host integer size, and verify source-located T0009 bounds diagnostics. Local wide positive/negative bindings and float casts are rejected before MIR on Linux/386 and amd64. Positive typed projections compile with Clang on both targets; runtime fixture preserves u8 negation, explicit narrowing and imported alias values. Positive/negative bundled fixtures proved red before repair and pass after rebuilding.
Changed/affected packages, full executable-fixture Go suite, vet, focused race, formatting and diff checks pass. That first local repair changed the constant bounds-query context; its validation is historical. The exact-length follow-up below also repairs the shared runtime element guard. Local implementation is uncommitted and awaits review/landing, so this issue remains open.
Local exact-bounds follow-up
Completed locally on
fix/constant-numeric-publicationin the approved #155/#154 review follow-up. Source bounds now compare exact integers, without host-sized length or index parsing. LLVM retains unsigned 64-bit array lengths, compares constant indexes exactly, and keeps index source locations for backend bounds rejection. The shared runtime element guard independently rejects negative signed indexes, including when unsigned length exceeds 2^63. Existing normalization, checked evidence, resolved bindings and trap-before-access ordering remain.Red/green coverage: three source-located pre-MIR rejection cases; six backend constant/malformed boundaries; constant/runtime borrowed-field LLVM compiled by Clang for 386 length 2^31 and amd64 lengths 2^63 and 2^63+1; eight native guard executions covering signed negatives, valid high unsigned indexes, equality and wider integers. New positive/negative large-array fixtures pass with rebuilt bundle. Large arrays are symbolic; huge-object allocation is not claimed.
Final validation passed with
CCACHE_DISABLE=1: focused and affected packages; bundle rebuild and seven affected fixture contracts; fullPEEPER_BIN=/home/itsfuad/Dev/Peeper/compiler/build/bin/peeper go test -count=1 ./...(all executable fixtures 21.190s);go vet ./...; typechecker/pipeline/LLVM race tests; formatting and diff checks. All eight #155 review items resolved locally, including three test/evidence simplifications. Implementation remains uncommitted and awaits review/landing; issue stays open.Local narrow-unsigned GEP follow-up
Completed locally on
fix/constant-numeric-publication(STEP 1E / review finding 11). Newly folded1f64 as u1selected a negative LLVM offset because GEP sign-extends narrow operands. After exact constant bounds validation,emitIndexPtrnow reuses existingemitCastto produce an i64 physical offset. Source/MIR checked type and value, unsigned lengths, located malformed/OOB rejection and runtime guards remain intact. No new production helper, API or state.Permanent red proof: 12 u1/u8/u24 read/store failures across 386/amd64, with 4 u64 controls passing; 18 source-to-MIR conversion failures; previous bundled fixture builds then exits 8 at wrong-element read. Green coverage: 36 backend read/store cases, 24 source/MIR/LLVM/Clang cases across both widths (including top-bit u8/u24 borrowed fields), and native fixture reads, stores, borrows and raw addresses selecting the correct slot while preserving guard/neighbor values.
Validation passed with
CCACHE_DISABLE=1: changed/affected packages; bundle rebuild; 18 affected positive/negative/trap/place/slice fixture contracts; fullPEEPER_BIN=/home/itsfuad/Dev/Peeper/compiler/build/bin/peeper go test -count=1 ./...(executable fixtures 19.622s, LSP 38.816s);go vet ./...; LLVM/pipeline/IR race checks; formatting, diff and rule audit. 386 is IR/object validation, not native execution; large-array controls are symbolic.Latest disposition: earlier findings 1-8 plus 11 fixed locally; 9 (single-use ABI helper), optional 10 (duplicate cast adaptation), and 12 (qualified imported constant bounds) remain Proposed with full repair plan. Qualified known-OOB gap remains tracked by #154; no completeness claim for that path. Implementation uncommitted and awaiting step review/landing; issues remain open.
Local qualified-constant follow-up
STEP 1F / review finding 12 is fixed locally on
fix/constant-numeric-publication, following user approval of STEP 1E. Existing evaluator symbol-read case now accepts Ident and ScopeResolution and queries original occurrence binding. SymbolConst gate, evalConstSymbol, defining-module PublishedConstant and numeric adaptation remain canonical. Variant dispatch stays first; no new production helper/API/state/store, foreign consumer cache, AST re-evaluation or lexical/import lookup fallback.Permanent red/green proof: 30 real-import index cases on Linux/386 and amd64 (16 exact source-located bounds errors before MIR/LLVM, 14 typed THIR/MIR positive cases including aliases, transitive publication, u1, source-width negation and narrowing), 8 shifts, 8 range width/entry/missing-return cases and 3 conditions whose warning appears exactly once at CFG, not Typechecked. Foreign-owner controls preserve published value after owner AST changes, reject missing publication despite poisoned cache, and keep unbound/nonconstant paths unsuccessful. Previous bundle missed imported errors and rejected valid consumer statics; rebuilt bundle passes new negative imported-query fixture and native imported u1 borrow/store, integer/float consumer-static and qualified-default/caller-shadow controls. Existing cache/cycle/default/fingerprint/enum/place behavior passes.
Final validation passed with
CCACHE_DISABLE=1: changed/affected packages; 386/amd64 LLVM/Clang objects; bundle rebuild; 27 affected fixture contracts; full suite with rebuilt PEEPER_BIN (all executable fixtures 46.738s, LSP 40.247s);go vet ./...; typechecker/project/pipeline/IR/LLVM race checks; formatting/diff/rule audit. Two test-local helpers consolidate real-file/import setup and shared THIR/MIR evidence assertions, removing copied traversal. Native execution is amd64; 386 is object validation and large-array controls are symbolic.Disposition: findings 1-8 and 11/12 Fixed locally; 9 (ABI helper) and optional 10 (duplicate cast adaptation) remain Proposed. STEP 1F awaits review; implementation uncommitted and issues remain open pending landing. Separate pre-existing parser ambiguity for bare qualified range endpoints before loop braces is tracked in #157; casted endpoints isolate evaluator tests. No parser repair or completeness claim for that syntax in this checkpoint.
Local ABI/cast cleanup and combined review
User-approved combined STEP 1G/1H is complete locally on
fix/constant-numeric-publication. Finding 9:ABIKeynow owns nominal-key/text fallback directly; single-useabiKeyLockeddeleted. Existing nil/invalid-ID guards, one read lock and raw reserved-shell access remain intact. Finding 10: explicit numeric cast returns its successfully validated value when canonical target/context types match; differing/nil queries and captured deferred destination conversion remain. Source-width intermediates, narrowing before widening, aliases/byte distinction, IEEE results and invalid-value rejection are preserved. No new production helper/API/state/instrumentation or performance claim.Meaningful invariant coverage passed both before and after cleanup: reserved-shell ABI identity before completion (public Type remains incomplete), inferred alias/byte casts without typing evidence, differing u16 context, aliased f32-to-f64 rounding and negative-zero widening. Existing imported constants, cache/cycles/finalization, exact bounds, source/MIR index types, guarded places, nominal/static-address and default/fingerprint contracts remain tested.
Final validation passed with
CCACHE_DISABLE=1: focused and affected packages; Linux/386 and amd64 LLVM/Clang checks; bundle rebuild; 28 affected executable fixture contracts; fullPEEPER_BIN=/home/itsfuad/Dev/Peeper/compiler/build/bin/peeper go test -count=1 ./...(executable fixtures 21.924s, LSP 38.820s);go vet ./...; IR/typechecker/project/pipeline/LLVM race checks; formatting/diff/deleted-helper/rule audits. Independent Standards review found zero hard violations and zero optional smells; independent Spec review found zero actionable defects and independently reran selected IR/typechecker/pipeline tests including numeric statics, recursive enums and interface consumers.Disposition: all 12 constant-evaluation review findings Fixed locally; supplemental target-reuse cleanup also Fixed. Implementation remains uncommitted and awaits human review/landing; this issue remains OPEN in 0.2 Language Foundations. PR #156 merge remains deferred. Native execution is amd64; 386 is object validation and large-array controls are symbolic. Parser issue #157 and other original audit work remain separate. Roadmap linkage retains existing token-scope blocker; no credential changes.
PR publication
Reviewed implementation is now published in PR #158: #158. Earlier local-progress sections preserve checkpoint history; the implementation is now committed and pushed.
28a3ea0; repo review skill/integration:b065375.fix/constant-binding-identityat80b3fd3; head:fix/constant-numeric-publicationatb065375. Depends on Preserve resolved bindings during constant evaluation #156; retarget tomainafter that PR lands.main, so their checks await retargeting; no non-author human approval recorded.read:projectpermission blocker; credentials/config unchanged.